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>
<Link to='/user'>user</Link>
<Link to='/Higher'>Higher</Link>
<Link to='/LongList'>LongList</Link>
<Link to='/Hook'>Hook</Link>
<Link to='/ErrorCom'>ErrorCom</Link>
<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
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
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
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
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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16