The principle of react router DOM

Keywords: Attribute Session Javascript React

Implement rendering different components according to different paths

There are two ways to achieve this:

HashRouter: it uses monitoring hash change (there is an event hashchange) to realize routing switching. It is a routing container, rendering sub components, and passing (Context context transfer) loading, history and other routing information to the next level sub components

window.addEventListener('hashchange',()=>{window.location.hash})

BrowserHistory: use H5Api to realize route switching. It is a route container, rendering subcomponent, and passing route information such as load, history to subcomponent

The history object provides an interface for manipulating the browser session history

The principle is to use the window.onpushstate method and window.onpoppstate method. When you add an entry (window.history.pushState()) to the browser address bar and click the forward / backward button of the browser, the routing information will be changed

window.history.pushState(state,title,url) adding a record to the browser history entry will not trigger the event, so you need to rewrite the pushState method and write an onpushstate method to listen to the pushState and then trigger the onpushstate method

!(function(history) {
  let oldPushState = history.pushState //Caching old pushState methods
  history.pushState = function(state, title, url) {
   if (typeof window.onpushstate === 'function') {
     window.onpushstate(state, title, url)
   }
  oldPushState.call(history, state, title, url)
}})(window.history)

window.onpopstate=function() {} will only trigger under certain actions of the browser, such as clicking backward and forward buttons (or calling history.back(), history.forward(), history.go() in JavaScript.)

Route: it is a routing rule. When path and browser address bar url match, components will be displayed. Generally, there are two attributes, path and component, and exact is an exact match (exact determines whether to exactly match isExact or not)

There are three ways to render a Route component:

  1. component is the simplest but cannot be judged logically
  2. Render is a function that can add logical judgment to render the return value of render after execution

One thing component and render have in common is that they render only when the path matches the address bar path

3.children is also a function, but it will render the return value of children after execution regardless of whether the path matches or not

Implementation:

export default class Route extends React.Component {
  static contextType = RouterContext
  render() {
    let paramsName = []
    let { pathname } = this.context.location;
    let { path="/", component: RouteComponent, exact = false ,render,children} = this.props
    let regexp = pathToRegExp(path, paramsName, { end: exact })
    paramsName = paramsName.map(item => item.name) 
    let matched = pathname.match(regexp) 
    let routeProps={
      location:this.context.location,
      history:this.context.history,
    }//Routing information
    if (matched) {//Match up to
      let [url,...values]=matched;
      let params=values.reduce((memo,cur,index)=>{
        memo[paramsName[index]]=cur
        return memo
      },{})//{id:1}
      let match={
        url,
        params,
        path,
        isExact:pathname===url
      }
      routeProps.match=match
      if(RouteComponent){
        return <RouteComponent {...routeProps}/>
      }else if(render){
        return render(routeProps)
      }else if(children){
        return children(routeProps)
      }else{
        return null
      }
      
    } else {//No match to
      if(children){
        return children(routeProps)
      }else{
        return null
      }
    }
  }
}

The components rendered through Route all have routing information (history, location, match)

Components not rendered by Route can be wrapped with withRoute if they want to get Route information

Link: provides the principle of navigation link using history.push(props.to)

Property to:string

         to:object

<li className="list-group-item" key={item.id}>
    <Link to={{ pathname: `/user/detail/${item.id}`, state: item }}>{item.username}        
    </Link>
</li>

Print props in the detail component and take props.location.state to get the value of the current object state - additional status data stored in the location. As soon as the hashRouter is refreshed, it will not become undefined

Realization:

<RouterContext.Consumer>
      {
        routerValue => {
          return <a {...props} onClick={()=>routerValue.history.push(props.to)}>{props.children}</a> 
        }
      }
</RouterContext.Consumer>

Switch: render the first child < route > or < redirect > matching the path (the same meaning as the switch case in js)

Redirect: redirection will navigate to a new location that will overwrite the current entry in the history stack

Property: to:string URL to redirect to

<Redirect to="/home/me" />

To: the location of the object to be redirected, where pathname is the url to be redirected, and state can carry information

<Redirect to={{pathname:'/login',state:{path:path}}}/>

from:string only the url provided by from can be redirected to the url specified by to

<Redirect from='/home' to="/" />

Realization:

export default (props) => {
  let routerValue = useContext(RouterContext)
  let pathname = routerValue.location.pathname;
  if (!props.from || (props.from && props.from === pathname)) {
    routerValue.history.push(props.to)
  }
  return null
}

NavLink:

You can have the principle of the exact attribute: when the attribute of to matches the address bar path, add an active class name to the component

Realization:

export default (props) => {
    let { to, children, exact } = props
    return <Route
        exact={exact}
        path={to}
        children={(routerProps) => {
        return <Link 
                className={routerProps.match ? 'active' : ''} 
                to={to}>{children}
            </Link>
        }
    } />
}

withRouter:

The function of the higher-order component with Route is that when a custom component is not rendered through the Route component, but you want to obtain the location, history, math and other attributes, you can use the package with Route to obtain the location, history, match and other attributes

Realization:

export default (OldComp)=>{
  return props=>{
    return <Route render={routerProps=>(<OldComp {...props} {...routerProps}/>)}/>
  }
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

47 original articles published, 33 praised, 110000 visitors+
Private letter follow

Posted by subrata on Sat, 22 Feb 2020 20:17:50 -0800