# React Router 基础

# 本质

react-router本质上,利用了history api的pushState, replaceState方法来控制路由地址,然后使用popstate, hashchange事件来监听变化,从而做出相应的视图变化

# 渲染流程

可以参考图: react-router-render-flow.png

如何做出视图变化? React View -> 点击事件 —> 路由变化 pushState/replaceState -> 事件监听变化 popstate hashchange -> react router接收到事件 更新视图

  1. 本质上返回的是a标签,只是对onclick方法做了处理
  2. 而在 click 方法里,最主要的处理就是禁用默认事件,也就是阻止 a 标签默认的跳转 href 的行为。避免直接跳转页面。然后使用 history 的 push(pushState) 和 replace(replaceState) 方法进行跳转
  3. push 方法里除了核心的 pushState 逻辑,还有另一个操作 setState. 详情可见 在它的逻辑里,它调用了之前注册的方法

# Router

  1. 本质上也是 React 组件。在渲染的时候,注册监听了事件
  2. 在静态 props 里可以看到,history 是必须的。印证了我们的常规用法。生成 history 后再传入组件内。<Router history={history}>
  3. 然后在生命周期 componentWillMount 里,使用 history.listen 注册了 setState 事件。当路由变化时,会自动触发 history 内的 setState 事件,进而触发当前传入的更新 state 的事件。原理就是上文的 Link 的内部逻辑,和之前分析的 history 的 push 方法里的逻辑和事件订阅发布逻辑
  4. 这就解释了,为什么 Link 里,点击后的事件,会导致当前 Router 的 state 的变化,进而改变 context.router 里的内容
componentWillMount() {
    const { children, history } = this.props
    
    this.unlisten = history.listen(() => {
      this.setState({
        match: this.computeMatch(history.location.pathname)
      })
    })
  }

# Route

  1. 在 Route 组件里,首先我们看到 render 里,由组件的内容类型来决定渲染是 component 或 render 或 children. 然后由 this.state.match 这个字段决定了当前的元素是否渲染
  2. 接着在上述源码里,this.state.macth 字段是在 componentWillReceiveProps 和初始化里可以看到。而这个变量,由一个比较重要的函数 computeMatch 返回。它是用来对比当前路由是否匹配,依此来决定渲染组件或者不渲染
  3. computeMatch 接收 nextProps 和 context.router 作为参数。首先判断是否处于 Switch 组件中,如果在其中,则直接走 Switch 安排的逻辑,它有着自己的一套计算匹配逻辑。否则,则继续判断。
  4. 接下来的核心判断,是获取 pathname, 通过 props.location || context.router.route.pathname 获取。然后将其作为参数,传入另一个重要方法 matchPath 中,做计算匹配的逻辑

# 思考

  1. match.path 和 match.url的区别?
path: "/topics/:id1"
url:  "/topics/components"   <==真实的url
  1. 在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的
陕ICP备20004732号-3