jingzhiMo.github.io
jingzhiMo.github.io copied to clipboard
react-router结构图解析
前言
最近在看一下react-router
的源码,看到react-rouer
的功能分散到几个packages
,也依赖基础包hisotry
,如果完整源码分析,可能会有点多,所以这次就弄一个张图来说明一下react-router
的使用。估计再过一阵子,v6
版本就要发了,这个图是v5.x
版本的,有点悲催。下面直接上图,主要说是在浏览器端运行的react-router
:
图有点点长,先来简单说一下不同颜色的区域表示什么:
- 蓝色:使用的用户,也就是开发者
- 绿色:不同的组件
- 黄色:通常是指一些方法
- 橙色:创建对象的函数
- 白色:浏览器基础对象
左边纵向的一列:
react-router
,react-router-dom
,history
表示不同的库,而window
就是浏览器。
下面就从对底层说起,捋一下这张图。
window
通常来说,路由库大部分基于两种:
一种是window.history
对象来控制url的改变
另外一种是通过location.hash
值来控制url的改变;
现在应该大部分都是用window.history
,如果要兼容部分低版本浏览器,可能就需要到location.hash
。而这两者都需要到location
的支持,才能获取更详细的信息。
history
需要注意的是,这是一个库,并不是window.history
的对象。
这个库是对页面路径的操作进行封装,目前是独立一个仓库,github 地址,支持上面所说的window.history
与location.hash
的两种路由情况;
分别对应BrowserHistory
与HashHistory
的创建函数,通过这两个创建函数创建出来的对象,都具有相同的API调用,因为history
这个库对这两种情况的路由进行了适配。通常这些通用的方法包含:
history.push()
history.replace()
history.go()
history.back()
// ... 等等
除此之外,还有定义一些路由过度的`promot`的逻辑等。
除此之外,还有还封装了MemoryHistory
的创建方法,看起来,是给到react-router-native
与部分测试的时候使用的。
react-router-dom
这个是react-router
的仓库其中一个package,是专门针对浏览器处理的路由封装。
通常我们是在这个库里面指定使用哪一种路由方式,BrowserHistory
or hashHistory
:
import { BrowserRouter as Router } from 'react-router-dom'
// or
import { HashRouter as Router } from 'react-router-dom'
而指定路由方式的时候,则调用hisotry
的两种不同createHistory
方法;获取创建的hisotry
返回对象。
react-router-dom
处理指定路由方式之外,还提供Link
与NavLink
的组件;通常来说;这两个组件用于跳转到不同的路由,这个时候跳转也是调用createHistory
返回对象的API,push
或者replace
react-router
react-router
通常是开发者直接调用的入口,例如路由组件的分发,当前参数获取等。
我们知道,从react-router-dom
引入BrowserRouter
或者HashRouter
来指定路由方式;其实这个时候,也返回一个Router
的组件,用于渲染页面路由的根组件。
Router
的根组件是后面所有组件的基础;后续所有组件,必须在这个根组件下。Router
,Switch
等组件层层嵌套。在这个过程中,RouterContext
是在整个组件过程中存在,这个context
就是用于不同组件间的数据共享;通常这个context
的数据为:
{
history, // createHistory 返回的对象
location, // 当前路径的信息
match // 当前路由匹配的信息
}
嵌套路由之间也是共用这个context
,从而达到路由数据之间的传递;而hooks
的调用也是基于useContext
来演变成不同的hooks
,例如useHistory
,useLocation
等。
那react-router-dom
的Link
更改的路由,怎么通知到context
更改呢?
在createHistory
的时候,返回的history
对象️监听方法listen
;而根组件Router
监听该方法,若发生改变,则更改RouterContext
的内容;从而做到不同组件间的数据通信。
小结
这篇文章对代码描述的不多,主要是对流程的处理进行梳理;了解到不同库之间的协作,与数据通信的技巧。具体实现还是得看源码。希望能够一图胜千言!!!喜欢给个star~