Introduction to react to the router

React-router contains three libraries, react-Router, react-router-dom, and react-router-native. React-router provides the most basic routing functions. In actual use, you can choose to install react-router-dom or react-router-native based on the application environment.

Yarn add react-router-dom or yarn add react-router-nativeCopy the code

The basic use

In React-Router, everything is a component. Router-router, link-link, Route, exclusive Switch, and redirection-Redirect all exist in the form of components

import React from "react";
import { BrowserRouter as Router, Link, Route, Switch } from "react-router-dom";
import HomePage from "./HomePage";
import LoginPage from "./LoginPage";
import UserPage from "./UserPage";

function RouterPage() {
  return (
    <div>
      <h3>RouterPage</h3>
      <Router>
        <nav>
          <Link to="/">Home page</Link> <Link to="/user">The user center</Link>{" "}
          <Link to="/login">The login</Link> <Link to="/product/123">goods</Link>
        </nav>
        <Switch>
          <Route path="/" exact component={HomePage} />
          <Route path="/user" component={UserPage} />
          <Route path="/login" component={LoginPage} />
          <Route render={()= > <h3>404 not found</h3>} / ></Switch>
      </Router>
    </div>
  );
}
export default RouterPage;

Copy the code

Route renders content in three ways

Children > Component >render

All three receive the same [route props], including match,location, and history, but children’s match is null if they do not match

The three modes are mutually exclusive and you can only select one of them

  • children:func

Sometimes, if you want to render something regardless of whether the location matches or not, you can use children, which works exactly the same as render, except that the location will be rendered regardless of whether the location matches or not

  • render:func

When you render, you’re just calling a function, but it, like component, can access all the route props

  • component:component

Render only if the location matches

Note: When using Component, Route creates a new React Element with the component you specify and react. createElement. This means that when you provide an inline function, each render creates a new component. This results in not updating an existing component, but simply uninstalling and mounting a new component. Therefore, when using inline rendering of inline functions, use render or children

Excerpt from source code:

BrowserRouter vs. HashRouter

1, HashRouter is the simplest. It does not require server rendering. BrowserRouter requires the server to return different HTML for different urls

BrowserRouter uses the HTML5 history API (pushState, replaceState and PopState events) to synchronize the UI of the page with the URL

3. The HashRouter does not support location.key and location.state. Passing parameters

4. Hash History can run without any server configuration

React-router transmits parameters in three ways

  • The first option is to write it in the path parameter of the route configuration and obtain it from the props. Match. params parameter
<Route path="/user/:id" />
Copy the code
  • The second is inLinkComponent parameterstoIt can bestringorobject{pathname, search, hash, state}To obtain the parameter, props. Location
<Link to={string || object}></Link>
Copy the code
  • The third way is throughhistory.pushAPI, the push parameter has two forms as follows: get the parameter from props. Location
history.push(string, [state]) // state is an object parameter
history.push({pathname, search, state}) // state is an object parameter
Copy the code

API source code implementation

Router

Common low-level interface for all Router components. Typically, one of the following higher-level routers is used:

  • BrowserRouter
  • HashRouter
  • MemoryRouter
  • NativeRouter
  • StaticRouter
import React, { Component } from "react";
import RouterContext from "./RouterContext";

class Router extends Component {
  static computeRootMatch(pathname) {
    return { path: "/".url: "/".params: {}, isExact: pathname === "/" };
  }
  constructor(props) {
    super(props);
    this.state = {
      location: props.history.location
    };

    // Listen for location changes
    this.unlisten = props.history.listen(location= > {
      this.setState({ location });
    });
  }

  componentWillUnmount() {
    // Cancel the listener
    if (this.unlisten) {
      this.unlisten(); }}render() {
    const { history, children } = this.props;
    return (
      <RouterContext.Provider
        value={{
          history.location: this.state.location.match: Router.computeRootMatch(this.state.location.pathname)}} >
        {children}
      </RouterContext.Provider>); }}export default Router;

Copy the code

BrowserRouter


uses the HISTORY API provided by HTML5 (pushState,replaceState, and popState events) to keep the UI and URL in sync

HashRouter


uses the hash part of the URL (window.location.hash) to keep the UI and URL in sync

MemoryRouter

Keep the history of the URL in the memory

(do not read, do not write to the address bar). Useful in testing and non-browser environments, such as React Native

Implement BrowserRouter

BrowserRouter

The history management object initializes and passes down, and location changes listen

import { createBrowserHistory } from "history";
import { Component } from "react";
import Router from "./Router";

class BrowserRouter extends Component {
  constructor(props) {
    super(props);
    this.history = createBrowserHistory();
  }
  render() {
    return <Router children={this.props.children} history={this.history} />; }}export default BrowserRouter;

Copy the code

Route


is the most important component of the React Router. Its basic responsibility is to render some UI when its path property matches a location

There are three ways to render using

:

  • component
  • render: func
  • children: func

Different ways are used in different cases, and only one of them should be used in the specified

Routing configuration, match detection, content rendering

Match: children> Component >render>null; child: function; render: node

Do not match children or null(render function only)

import React, { Component } from "react";
import matchPath from "./matchPath";
import RouterContext from "./RouterContext";

class Route extends Component {
  render() {
    return (
      <RouterContext.Consumer>{context => { const { location } = context; const { children, component, render, path, computedMatch } = this.props; const match = computedMatch ? computedMatch : path ? matchPath(location.pathname, this.props) : context.match; // location.pathname === path const props = { ... context, match }; // match children, component, render, null // do not match children(function) // return match? React.createElement(component):null return (<RouterContext.Provider value={props}>
              {match
                ? children
                  ? typeof children === "function"
                    ? children(props)
                    : children
                  : component
                  ? React.createElement(component, props)
                  : render
                  ? render(props)
                  : null
                : typeof children === "function"
                ? children(props)
                : null}
            </RouterContext.Provider>
          );
        }}
      </RouterContext.Consumer>); }}export default Route;

Copy the code

Link

Jump links, handle click events

Parameters: : string | object

A string or object in the form of links, through the pathname, search, hash, such as the state to create the replace: bool when set to true, after click on the link will replace the current entry in the history stack, rather than adding a new entry. The default is false

Other attributes such as title, ID,className, etc

import { useContext } from "react";
import RouterContext from "./RouterContext";

function Link({ children, to, ... restProps }) {
  const { history } = useContext(RouterContext);
  const handleClick = e= > {
    e.preventDefault(); // Block the default click behavior
    // command jump
    history.push(to);
  };
  return (
    <a href={to} {. restProps} onClick={handleClick}>
      {children}
    </a>
  );
}
export default Link;

Copy the code

Switch

The first

or

child to render to match the path


will render only one route

import React, { Component } from "react";
import matchPath from "./matchPath";
import RouterContext from "./RouterContext";

class Switch extends Component {
  render() {
    return (
      <RouterContext.Consumer>{context => { const { location } = context; let match; // Tag matches let element; // children React.children. ForEach (this.props. Children, child => { if (match == null && React.isValidElement(child)) { element = child; match = child.props.path ? matchPath(location.pathname, child.props) : context.match; }}); return match ? React.cloneElement(element, { computedMatch: match }) : null; }}</RouterContext.Consumer>); }}export default Switch;

Copy the code

Hooks to realize

Implement useHistory, useLocation, useRouteMatch, useParams, and so on

import { useContext } from "react";
import RouterContext from "./RouterContext";

// Custom hooks
export function useHistory() {
  return useContext(RouterContext).history;
}

export function useLocation() {
  return useContext(RouterContext).location;
}

export function useRouteMatch() {
  return useContext(RouterContext).match;
}

export function useParams() {
  const match = useContext(RouterContext).match;
  return match ? match.params : {};
}

Copy the code