miniReactRouterDom

12/11/2020 react-router-domminireact

# 原理

  • 利用 React.createContext 创建可以深度注入的公共变量
  • 由 Router(BrowserRouter/HashRouter)向子组件提供 location,history 等必要路由信息
  • 在 Link 调用 history 的对应更新路由方法(push)
  • 在 Route 中进行对应匹配,决定是否进行展示 children/component/render 内容

# mini 代码

实现较为简单,并且只做了 hash 模式,未实现嵌套路由

# demo 使用

与 react-router 相比 支持功能相对简单很多,基础使用即可

demo
import React from 'react'
import { BrowserRouter as Router } from './BrowserRouter'
import { Link } from './link'
import { Route } from './router'
// 一系列的组件,未进行引用了
export default () => {
  const th = useContext(ThemeContext)
  return (
    <Router>
      <Link to='/'>index</Link>&nbsp;
      <Link to='/user'>user</Link>&nbsp;
      <Link to='/Higher'>Higher</Link>&nbsp;
      <Link to='/LongList'>LongList</Link>&nbsp;
      <Link to='/Hook'>Hook</Link>&nbsp;
      <Link to='/ErrorCom'>ErrorCom</Link>&nbsp;
      <hr /> <div>{th}</div>
      <Suspense fallback={<>加载路由</>}>
        <ErrorB>
          <Route path='/' exact component={Index}></Route>
          <Route path='/user' exact component={User}></Route>
          <Route path='/Higher' exact component={Higher}></Route>
          <Route path='/LongList' exact component={LongList}></Route>
          <Route path='/Hook' exact component={Hook}></Route>
          <Route path='/ErrorCom' exact component={ErrorCom}></Route>
        </ErrorB>
      </Suspense>
    </Router>
  )
}
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

# 全局的 context

在 react 使用 context 在插件或者框架中非常常见,但是不能过渡使用

context
import { createContext, } from 'react';
export const routerContext = createContext()
1

# Router

应该有三种 router ,BrowserRouter/HashRouter/absRouter,后者用于服务端使用

BrowserRouter
import React, { Component } from 'react'
import { createBrowserHistory } from 'history' // 一个三方的库,封装了history相关的操作,可以生成history模式以及hash模式
import { routerContext } from './context'


export class BrowserRouter extends Component {
  constructor(props) {
    super(props)
    const history = new createBrowserHistory()
    this.state = { history, location: history.location }
    this.unLisen = history.listen(this.historyChange)
  }
  componentWillUnmount() {
    this.unLisen && this.unLisen()
  }
  historyChange = (location, action) => {
    this.setState({ location })
  }
  render() {
    return (
      <routerContext.Provider value={this.state}>
        {this.props.children}
      </routerContext.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
link
import React, { Component } from 'react'
import { routerContext } from './context'

export class Link extends Component {
  static contextType = routerContext
  constructor(props) {
    super(props)
  }
  handleClick = (e) => {
    e.preventDefault()
    this.context.history.push(this.props.to)
  }
  render() {
    return <a href={this.props.to} onClick={this.handleClick}>{this.props.children}</a>
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# Route

具体渲染的地方

Route
import React, { Component, createElement } from 'react'
import { routerContext } from './context'

export class Route extends Component {
  static contextType = routerContext
  constructor(props) {
    super(props)
  }
  render() {
    const { location } = this.context
    const { path, componnet, redner, children } = this.props
    // 此处应该是复杂的对比过程
    const match = location.pathname === path
    // 此处应该还要兼容render,children等各种情况
    return match ? createElement(componnet) : null
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Last Updated: 12/11/2020, 11:46:45 AM