react-router&dom的源码分析

# react-router-dom

react-router-dom是react的路由,它帮助我们在项目中实现单页面应用,它提供给我们两种路由一种基于hash段实现的HashRouter,一种基于H5Api实现的BrowserRouter

环境配置

npm i react react-dom react-router-dom @babel/preset-react -D
1

webpack.config.js,在js的options配置加一个preset

index.js改成这样。

import React from 'react'
import ReactDom from 'react-dom'
import { BrowserRouter, Route, Link } from 'react-router-dom'

function App() {
    return (
        <BrowserRouter>
            <Link to='/home'>home</Link>
            <Link to='/about'>about</Link>
            <Route path='/home' render={()=><div>home</div>}></Route>
            <Route path='/about' render={()=><div>about</div>}></Route>
        </BrowserRouter>

    )
}
ReactDom.render(<App></App>,document.getElementById('root'))
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

public/index.html

<div id="root"></div>
1

# browserRouter实现

首先我们在index.js新建一个BrowserRouter.js文件,我们来实现自己BrowserRouter。

既然要实现BrowserRouter,那这个文件就得有三个组件BrowserRouter,Route,Link。

# BrowserRouter组件

BrowserRouter组件主要做的是将当前的路径往下传,并监听popstate事件,所以我们要用Consumer

# Rouer组件的实现

Router组件主要做的是通过BrowserRouter传过来的当前值,与Route通过props传进来的path对比,然后决定是否执行props传进来的render函数

# Link组件的实现

Link组件主要做的是,拿到prop,传进来的to,通过PushState()改变路由状态,然后拿到BrowserRouter传过来的onChangeView手动刷新视图

使用

把刚才在index.js使用的react-router-dom换成这个文件路径就OK

# hashRouter的实现

hashRouter就不一个一个组件的说了,跟BrowserRouter大同小异,直接贴完整代码

const { Consumer, Provider } = React.createContext();

export class BrowserRouter extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      currentPath: this.getParams.bind(this)(window.location.pathname),
    };
  }

  onChangeView() {
    const currentPath = this.getParams.bind(this)(window.location.pathname);
    this.setState({ currentPath });
  }

  getParams(url) {
    return url;
  }

  componentDidMount() {
    window.addEventListener("popstate", this.onChangeView.bind(this));
  }

  componentWillUnmount() {
    window.removeEventListener("popstate", this.onChangeView.bind(this));
  }

  render() {
    return (
      <Provider
        value={{
          currentPath: this.state.currentPath,
          onChangeView: this.onChangeView.bind(this),
        }}
      >
        <div>
          {React.Children.map(this.props.children, function (child) {
            return child;
          })}
        </div>
      </Provider>
    );
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44

image-20201018234242041

上次更新: 2022/04/15, 05:41:29
×