# React Router 基础
# 本质
react-router本质上,利用了history api的pushState, replaceState方法来控制路由地址,然后使用popstate
, hashchange
事件来监听变化,从而做出相应的视图变化
# 渲染流程
可以参考图: react-router-render-flow.png
如何做出视图变化? React View -> 点击事件 —> 路由变化 pushState/replaceState -> 事件监听变化 popstate hashchange -> react router接收到事件 更新视图
# Link
- 本质上返回的是a标签,只是对onclick方法做了处理
- 而在 click 方法里,最主要的处理就是禁用默认事件,也就是阻止 a 标签默认的跳转 href 的行为。避免直接跳转页面。然后使用 history 的 push(pushState) 和 replace(replaceState) 方法进行跳转
- push 方法里除了核心的 pushState 逻辑,还有另一个操作 setState. 详情可见 在它的逻辑里,它调用了之前注册的方法
# Router
- 本质上也是 React 组件。在渲染的时候,注册监听了事件
- 在静态 props 里可以看到,history 是必须的。印证了我们的常规用法。生成 history 后再传入组件内。
<Router history={history}>
- 然后在生命周期 componentWillMount 里,使用 history.listen 注册了 setState 事件。当路由变化时,会自动触发 history 内的 setState 事件,进而触发当前传入的更新 state 的事件。原理就是上文的 Link 的内部逻辑,和之前分析的 history 的 push 方法里的逻辑和事件订阅发布逻辑
- 这就解释了,为什么 Link 里,点击后的事件,会导致当前 Router 的 state 的变化,进而改变 context.router 里的内容
componentWillMount() {
const { children, history } = this.props
this.unlisten = history.listen(() => {
this.setState({
match: this.computeMatch(history.location.pathname)
})
})
}
# Route
- 在 Route 组件里,首先我们看到 render 里,由组件的内容类型来决定渲染是 component 或 render 或 children. 然后由 this.state.match 这个字段决定了当前的元素是否渲染
- 接着在上述源码里,this.state.macth 字段是在 componentWillReceiveProps 和初始化里可以看到。而这个变量,由一个比较重要的函数 computeMatch 返回。它是用来对比当前路由是否匹配,依此来决定渲染组件或者不渲染
- computeMatch 接收 nextProps 和 context.router 作为参数。首先判断是否处于 Switch 组件中,如果在其中,则直接走 Switch 安排的逻辑,它有着自己的一套计算匹配逻辑。否则,则继续判断。
- 接下来的核心判断,是获取 pathname, 通过 props.location || context.router.route.pathname 获取。然后将其作为参数,传入另一个重要方法 matchPath 中,做计算匹配的逻辑
# 思考
- match.path 和 match.url的区别?
path: "/topics/:id1"
url: "/topics/components" <==真实的url
- 在Hash模式下如何进行路由跳转
this.props.history.push(`${url}`, { nodeType: nodeType }) //提示错误 Warning: hash history cannot push state it is ignored
this.props.history.push({ pathname: `${url}`, state: { nodeType: nodeType }}) //OK的
← 学习链接 React router 实践 →