React Router 原理分析

前言

如果我们开发 React 的 SPA(单页应用 single page web application),不可避免的接触 router 的概念,但是他是怎么实现的呢?本次基于 react-router v4

HashRouter

HashRouter其实原理是通过window.addEventListener('hashchange', callback)事件来实现的,其特色就是会出现一个#

井号的含义

其实是锚点,指的是阅读到什么位置,最常见的就是上面这个标题,查看html后你会发现id等于井号的含义,当点击右侧阅读导航的时候,浏览器url后面就会加上#井号的含义。

特性

  1. 由于#实际上是控制浏览器动作的,对服务器没有任何作用,所以在它之后的东西并不会涵盖在http请求:

    https://yeungkc.com/2019/07/06/web-react-router/#井号的含义
    实际上 http 请求只有 https://yeungkc.com/2019/07/06/web-react-router/

  2. 同因为是控制浏览器动作,改变#只会滚动到相应的位置,并不会重新加载网页
  3. 改变#会改变访问历史,即是你点击多次标题导致滚动位置变化,后退的时候也是回到之前的位置
  4. window.location.hash可以读取和写入,写入的时候增加历史记录

BrowserRouter

除非低版本没办法,拥有一个多余的#总是不好的,更为优雅的方法是利用window.addEventListener('popstate', callback)方法来进行前进后退的监听,甚至在不用使用window.location.hash = '#foo'这种方式,直接使用window.history来控制变得优雅简单许多,可惜的是这个是HTML5API,可幸的是大部分都有用上了

使用

  1. 监听

    1
    2
    3
    window.addEventListener("popstate", e => {
    const path = e.state && e.state.path;
    });
  2. History.back():移动到上一个网址,等同于点击浏览器的后退键。对于第一个访问的网址,该方法无效果

  3. History.forward():移动到下一个网址,等同于点击浏览器的前进键。对于最后一个访问的网址,该方法无效果
  4. History.go():接受一个整数作为参数,以当前网址为基准,移动到参数指定的网址,比如go(1)相当于forward()go(-1)相当于back()。如果参数超过实际存在的网址范围,该方法无效果;如果不指定参数,默认参数为 0,相当于刷新当前页面
  5. History.pushState():方法用于在历史中添加一条记录,有三个参数
    state:一个与添加的记录相关联的状态对象,主要用于popstate事件。该事件触发时,该对象会传入回调函数。也就是说,浏览器会将这个对象序列化以后保留在本地,重新载入这个页面的时候,可以拿到这个对象。如果不需要这个对象,此处可以填null
    title:新页面的标题。但是,现在所有浏览器都忽视这个参数,所以这里可以填空字符串
    url:新的网址,必须与当前页面处在同一个域。浏览器的地址栏将显示这个网址
  6. History.replaceState():用来修改History对象的当前记录,其他都与pushState()方法一模一样