React-router + history = react-router-dom; react-router + history = react-router-dom

First, basic principles

The result of printing props for the routing component is as follows:

Routing principles:

Router The Router manages each Route entry.

The Router and Route communicate through the context. Create a RouterContext object on the Router with a value attribute of {history, location, match}. When we visit the page, we get the PathName property in Location and the Path property of Route and match it and render it.

Second, implementation ideas

1. Implement the react – the router

The React-router eventually exposes a router withhistoryProperties of theRouterComponents,historyProperty is provided by the history librarycreateHashHistory()Method to get an instance object of hashHistory ashistoryThe value of the incomingRouterComponents.

The Router component wraps all routes and communicates through the context. Because the routing component receives props containing {history, location, match}, we create a context object on the Router and provide the value property with the Provider, which is {history, location, match}.

History: props. History // the history object passed to the router component in the react-router: Location // The latest path to the browser history object match: // implemented in a later articleCopy the code

2. To realize the Route

All a Route needs to do is compare its path to the location. Pathname provided by the Provider and render the corresponding component if they are the same.

2-1. Get the pathname

Since the Router and Route communicate through the context, we can get the Location object directly from the context, and thus get the PathName attribute.

2 – (2) access path

We print inside the Route componentpropsAnd get what we pass to it when we use itpathandcomponentProperties.

2-3. Render the React element

Take the PathName and path and compare them to see if they are the same. If they are, render the component corresponding to the path.

Enter the URL in the browser address bar and the corresponding component can be rendered after refreshing. But the page doesn't refresh automatically. Why? Because we're not listening for the URL yet.Copy the code

3. Implement listening

On the Router, add a Listen event to history (the history built-in object can intercept and execute the Listen event). The input of this event is the new URL in the address bar, so we can directly update the value of location in the component to this input.

Three, code implementation

1. src/index.js

import React from "react";
import ReactDOM from "react-dom";
import { HashRouter as Router, Route } from "./react-router-dom";
import Home from "./components/Home";
import User from "./components/User";
import Profile from "./components/Profile";

ReactDOM.render(
  <Router>
    <div>{/ *<Route path="/" component={Home} />* /}<Route path="/" component={Home} exact />
      <Route path="/user" component={User} />
      <Route path="/profile" component={Profile} />
    </div>
  </Router>.document.getElementById("root"));Copy the code

2. src/components

2-1. components/Home.js

import React, { Component } from 'react'

export default class Home extends Component {
  render() {
    return (
      <div>
        <p>Home</p>
      </div>)}}Copy the code

2-2. components/User.js

import React, { Component } from 'react'

export default class User extends Component {
  render() {
    return (
      <div>
        <p>User</p>
      </div>)}}Copy the code

2-3. component/profile.js

import React, { Component } from "react";

export default class Profile extends Component {
  render() {
    console.log(this.props);
    return (
      <div>
        <p>Profile</p>
      </div>); }}Copy the code

3. src/react-router-dom

3-1. react-router-dom/index.js

export * from ".. /react-router";
export { default as HashRouter } from "./HashRouter";
export { default as BrowserRouter } from "./BrowserRouter";
Copy the code

3-2. react-router-dom/HashRouter.js

import React, { Component } from "react";
import { Router } from ".. /react-router";
import { createHashHistory } from "history";

export default class HashRouter extends Component {
  history = createHashHistory();

  render() {
    return <Router history={this.history}>{this.props.children}</Router>; }}Copy the code

3-3. react-router-dom/BrowserRouter.js

import React, { Component } from "react";
import { Router } from ".. /react-router";
import { createBrowserRouter } from "history";

export default class BrowserRouter extends Component {
  history = createBrowserRouter();

  render() {
    return <Router history={this.history}>{this.props.children}</Router>; }}Copy the code

4. src/react-router

4-1. react-router/index.js

export { default as Router } from "./Router";
export { default as Route } from "./Route";
export { default as RouterContext } from "./RouterContext";
Copy the code

4-2. react-router/RouterContext.js

import React from "react";

export default React.createContext({});
Copy the code

4-3. react-router/Router.js

import React from "react";
import RouterContext from "./RouterContext";

class Router extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      // The history object has the latest path
      location: props.history.location,
    };

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

  render() {
    let value = {
      history: this.props.history,
      location: this.state.location,
    };

    return (
      <RouterContext.Provider value={value}>
        {this.props.children}
      </RouterContext.Provider>); }}export default Router;
Copy the code

4-4. react-router/Route.js

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

export default class Route extends Component {
  static contextType = RouterContext;
  render() {
    console.log(this.props);
    // Each route entry compares the location. Pathname provided by the Provider to its own path
    const { history, location } = this.context;
    const { path, component: RouteComponent } = this.props;
    const match = location.pathname === path;
    const routeProps = { history, location };
    // React element to render
    let element = null;
    if (match) {
      element = <RouteComponent {. routeProps} / >;
    }
    returnelement; }}Copy the code

Four,

  1. The import file introduces the Router routing container and the Route routing entry component: called from the RoutercreateHashHistoryMethods to obtainhistoryObject that is passed to the Router as a property.
  2. Imported from the Router filecontext, internal constructionvalueObject:
    • History: passed in step 1
    • Location: The default is the location provided by the browser’s history object

    createcontextAfter theRouterContextComponent, and passed invalueObject and expose the component. Render the Route entry subcomponent.

  3. In the Route file, the corresponding component is rendered for matching the path.