preface

When a react-route Link or Push redirect is used, the page is not refreshed, but the Url is changed. When a react-route Link is used, the Url is changed, but the page is not refreshed. So my sister studied the source code of react- Route from this direction, to share with friends.

Decrypt – Click the back button but the page does not refresh

1. HashRouter analysis

Use location.hash to change urls without refreshing the page

location.hash=hash
Copy the code

Then listen for the browser’s return event via onHashchange

window.addEventListener('onhashchange', (event) => {
    changeDisplayName();// Replace what is displayed
});
Copy the code

2. BrowserRouter analysis

Push is implemented using native history.pushState, and history.replace is implemented using native history.replaceState.

changeDisplayName();// Replace what is displayed
window.history.pushState(null.null, newUrl);
Copy the code

It then listens for browser return events via popState

window.addEventListener('popstate', (event) => {
    changeDisplayName();// Replace what is displayed
});
Copy the code
case

The code is change Page with History package on codepen

import React, { useEffect, useState, useRef, Component } from 'react';
const MapPage=(a)= >{
  return <div>MapPage</div>
}
const RankPage=(a)= >{
  return <div>RankPage</div>
}

function ConPage() {
  const[Page, setPage] = useState('rank');

  useEffect((a)= >{
  
    window.addEventListener('popstate', (event) => {
      console.log("location: " + document.location + ", state: " + JSON.stringify(event.page));
      let val;
      if(event.page=='rank') {
        val='rank'
      }else{
        val='map'
      }
      console.log('useEffect',val) setPage(val) }); }, [])const _changePage = (a)= > {
    if(Page=='rank') {
      setPage('map')
      window.history.pushState({page:'map'}, null.'http://dev.jd.com:10086/con?pId=map');
     }else{
      setPage('rank')
      window.history.pushState({page:'rank'}, null.'http://dev.jd.com:10086/con?pId=rank'); }}return (
    <div>
      <div onClick={_changePage} className='btnTest'>Switch routing</div>

      {Page=='rank' &&
        <RankPage />
      }
      {Page=='map' &&
      <MapPage />
    }
    </div>)}export default ConPage
Copy the code

3. Combine with history

The popState and onhashchange methods are not compatible with Android4.4.4, so you need to introduce the NPM package history, which contains compatibility code, if not compatible, you can jump directly to window.location.href.

Change URL with History Package on codepen

const history = History.createBrowserHistory();
const Location = history.location;

const MapPage=(a)= >{
  return <div>MapPage</div>
}
const RankPage=(a)= >{
  return <div>RankPage</div>
} 

function ConPage() {
  const[Page, setPage] = React.useState('rank');

  React.useEffect((a)= >{
   history.listen((Location, action) = > {
      console.log(action, Location.state);
      if(Location.state.page && Location.state.page=='map'){
        setPage('map')}else{
        setPage('rank')}}); }, [])const _changePage = (a)= > {
    if(Page=='rank') {
      history.push('/con? pId=map', {page: 'map' });
     }else{
      history.push('/con? pId=rank', {page: 'rank'}); }}return (
    <div>
      <button onClick={_changePage} className='btnTest'>Switch routing</button>
      {Page=='rank' &&<RankPage />}
      {Page=='map' &&<MapPage />}
    </div>
  )
}

ReactDOM.render(
<ConPage />,
    document.getElementById('root'),
  )
Copy the code

Four, view the display page

The source code

The react – in the router RouterContext. Js

//TODO:You can also use React. CreateContext
import createContext from "mini-create-react-context";

const createNamedContext = name= > {
  const context = createContext();
  context.displayName = name;

  return context;
};

const context = /*#__PURE__*/ createNamedContext("Router");
export default context;

Copy the code
Analysis of the

The Context object accepts a property named displayName, of type string. React DevTools uses this string to indicate what context should display.

For example, the following components will be displayed as MyDisplayName in DevTools:

const MyContext = React.createContext(/* some value */);
MyContext.displayName = 'MyDisplayName'; Provider < myContext. Provider> // "myDisplayName. Provider" in DevTools < myContext. Consumer> //" myDisplayName. Consumer" in In the DevToolsCopy the code

Happy coding .. 🙂

A link to the

The original blog

react-router github

history github

Popstate interface API

OnHashchange compatibility

change URL with history package

Change URL without refreshing page