Redux: Redux-Saga: Redux-Saga: Redux-Saga: Redux-Saga: Redux-Saga: Redux-Saga: Redux-Saga: Redux-Saga: Redux-Saga: Redux-Saga: Redux-Saga: Redux-Saga: Redux-Saga

To preview the react-Router implementation, click hereCodesandbox may be slow

This section making code: Build – your own – XXX – -based – on – Javascript, in the library of the react – the router directory, the wheels of the follow-up will also in the update below, your implements these wheels, those features and apis to forget all forget, how can it do

How to implement the react-router-dom? Its function can be a index.js, do not need a lot of other components to elaborate..

Setup:

A very general index.js file:

import React, { Component } from 'react' import ReactDOM from 'react-dom'; import App from './components/App'; import { HashRouter as Router, Route, Switch,Link} from 'react-router-dom' let User = () => <div>User</div Let Home = () => <div> <Router> <h6> < link to={{pathName: '/ Home /user', state: {day: 'Friday' }}}>user</Link> <Link to="/home/bitch">bitch</Link> </h6> <Switch> <Route path="/home/user" component={HomeUser}></Route> <Route path="/home/bitch" component={HomeBitch}></Route> </Switch> </Router> </div>; Class HomeUser extends Component {render() {console.log('this.props. Location ', This. Props. The location) return (< div > {this. Props. The location. The state. The day} -- -- -- -- -- nihao < / div >)}} / under/Home let HomeBitch component HomeBitch = () => <div>HomeBitch</div> ReactDOM.render( <div> <Router> <h1> <Link To = {{the pathname: '/ home', state: 'keymap'}} > home page < / Link > < Link to = "/ user" > user < / Link > < / h1 > < Switch > < the Route path = "/ home" component={Home}></Route> <Route path="/user" component={User}></Route> </Switch> </Router> </div> , document.getElementById('root'));Copy the code

Achieve goals:

Implement HashRouter

2. Implement Route

3. Implement the Switch

4. Implement Link

5. Implement route parameter transfer through the object

Ok, these are just a few small goals

First analysis:

  1. The first thing you want to implement is all the React components, which have two default parameters, props and context
  2. To pass data between these components, you need to use the global object Context. To do this, you need to define childContextTypes in the ancestor component, use the package prop-Types, and define getChildContext, which returns the data you want to pass, ContextTypes are then defined in the descendant component to receive.
  3. We know that in the use of react-router-dom, the methods of obtaining pathname and state are respectivelythis.props.location.pathname.this.props.location.stateThis determines the state structure of the top-level component of the HashRouter, and listens for the Hashchange method in this component, which rerenders the DOM when the hash changes
  4. Switch actually does not do a lot of things inside, in real use, you do not introduce Switch, Switch to div is no problem, as for why, in the process of writing code will explain
  5. In the react-router-dom, Click Link to call this.props.history. Push (pathName), which is obviously passed from the HashRouter component through the context, and which also determines that there must be a push method in the data passed by the context.

Ok, something like this. Here’s the code:

Create react-router/hashrouter.js

HashRouter components:

import React, { Component } from "react";
import PropsTypes from "prop-types";

class HashRouter extends Component {
  static childContextTypes = {
    location: PropsTypes.object,
    history:PropsTypes.object
  };
  constructor(props) {
    super(props);
    // State has only one location object, location has two properties, state and pathName
    this.state = {
      location: {state: {},// Click Link to pass the parameter through state
        pathname: window.location.hash.slice(1) | |"/"  // Define the current hash, represented by pathName}}; } getChildContext() {let _this = this;
    return {
      // Pass the current location through context as well
      location: this.state.location,
      // Click Link to call this.props. History. push(pathname) which is the push method called
      history:{
        // Go back to the push method when you see the Link component,
        push(path){
          // If path is an object, deconstruct it to get state
          if(typeof path === 'object') {let {pathname,state} = path;
            _this.setState({
              // New location objectlocation:{ ... _this.state.location,state,pathname } },()=>{window.location.hash = pathname; })}else{
            // If path is a string, set the hash to that path directly, triggering a hashchange re-rendering
            _this.setState({
              location: {... _this.state.location,pathname:path
              }
            },()=>{
              // Path is a string
              window.location.hash = path; })}}}}; } componentDidMount() {// If you access localhost:3000 it will become localhost:3000/#/, that's how it works
    window.location.hash = window.location.hash || "/";
    let render = (a)= > {
      // setState will cause the UI to re-render, storing the changed hash in state
      this.setState({location: {... this.state.location,pathname:window.location.hash.slice(1) | |'/'}});
    };
    // Listen for changes to the hash, and when the hash changes, trigger render
    window.addEventListener("hashchange", render);
  }
  render() {
    As we all know, the render function must have a unique root node
    // If there were no switch, there would be 3 Route components returned, and no unique root node
    // So you need the Switch component to provide the root node, so you can render div just as well...
    return this.props.children; }}export default HashRouter;

Copy the code

The Switch component:

import React, { Component } from 'react'
import PropTypes from 'prop-types';
import pathToRegexp from 'path-to-regexp'

export class Switch extends Component {
    static contextTypes = {
        location : PropTypes.object
      }
    render(){
        return this.props.children; }}export default Switch

Copy the code

The Route module:

import React, { Component } from "react";
import PropsTypes from "prop-types";
import PathToRegexp from 'path-to-regexp'

export class HashRouter extends Component {
  static contextTypes = {
    location : PropsTypes.object
  }
  render() {
    debugger
      let {path,component:Component} = this.props;
      let {location:{pathname}} = this.context;
      / / note: this path = = the pathname | | the pathname. StartsWith (path) is wrong all matches to the '/', will be in a infinite loop
    	
      / / it is also possible that the if (path = = the pathname | | (path! =='/'&&pathname.startsWith(path))){
    
    // The react-router is a router that uses a path-to-regexp library
        if(PathToRegexp(path,[],{end:false}).test(pathname)){
          // If the current route is/XXX /yyy, the components corresponding to/XXX and/XXX /yyy should be displayed
          
          // Path matching renders the component corresponding to the parameters component and passes location and history as properties to the child components, which can be called through this.porps.history. XXX and this.porps.location.xxx
          return <Component location={this.context.location} history={this.context.history}/>;
      }
        return null;
  }
}

export default HashRouter;
Copy the code

The Link component:

import React, { Component } from 'react' import PropTypes from 'prop-types'; export class Link extends Component { static contextTypes = { history:PropTypes.object } render() { return ( // Direct call context passed the push method of < a onClick = {() = > {this. Context. History. Push this. Props. (to)}} > {this. Props. Children}}} < / a >) export default LinkCopy the code

Code and comments detailed so far, if you help, might as well like attention to go a wave ~ look at the past article, I believe you will receive goods surprise ~