ZF_react react-router起步 React路由原理 简单实现Router Route createHashRouter createBrowserRouter。

Posted lin-fighting

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ZF_react react-router起步 React路由原理 简单实现Router Route createHashRouter createBrowserRouter。相关的知识,希望对你有一定的参考价值。

React路由原理

  • 不同的路由渲染不同的组件
  • 有两种实现方法
    • HashRouter: 利用hash实现路由切换
    • BrowserRouter:实现h5 Api实现路由的切换

HashRouter

hash地址切换的时候页面不会刷新,使用window.location.hash读写hash地址,可以给浏览器造成一个跳转的假象。
比如我在#/a跳到了#/b,页面没有刷新,但是点击浏览器的回退按钮可以回退到#/a页面。
实现:

通过监听hash改变去渲染不同的页面。

BrowserRouter

1 history

H5规范提供了一个history接口,包括两个方法:history.pushState(),
history.replaceState()还有一个事件,window.onpopState。

  • pushState

    • history.pushState(stateObject, title, url)
    • 第一个参数适用于存储该url对应的状态对象,可以在onpopState事件中获取,也可以在history对象中获取。
    • 第二个参数是标题,目前浏览器暂未实现
    • 第三个参数是设定的url
    • pushState函数向浏览器的历史堆栈中压入一个url为设定值的记录,并将历时堆栈的当前指针指至栈顶
  • replaceState

    • 该接口与pushState参数相同,含义相同
    • 唯一的区别在于,replaceState是替换浏览器历时堆栈的当前历史记录为设定的Url,就是会代替当前的Url
    • 并且replaceState不会改动浏览器历史堆栈的当前指针。
  • onpopstate

    • window的属性
    • 会在调用浏览器的的前进,后退,以及执行history.forward,history.back,history.go触发,这些操作都有一个特性,改变了浏览器的当前指针。
    • 在不改变document的前提下,一旦当前指针改变就会触发onpopState事件。
  • 浏览器对每个页面维护一个history栈,执行pushState函数可压入设定的url至栈顶,同时修改当前指针。

  • 当执行back和forward操作的时候,history栈大小不会改变,仅仅移动当前的指针位置

  • 若当前指针在history栈的中间位置,此时执行pushState会在指针当前位置添加此条目,并成为新的栈顶。(比如现在栈里面是,1,2,3。回退到2时,在pushState到4,此时栈变成124,3会被替代掉。)
    实现:
    重写onpushstate方法


    pushState不会引起onpopstate改变,

    监听pushstate方法,渲染不同的组件页面。
    这就是路由的实现原理。因为单纯的pushState仅改变网址,网页不会真的跳转,也不会获取到新的内容,本质上网页还停留在原页面
    。是我们通过监听改变去渲染不同的页面

原理

react-router中的HashRouter和BrowserRouter像是react的一个借助context的包含了History的高阶组件。用来控制路有变化并渲染不同的组件
先看react-router-dom的使用
hashRouter

Router是容器,所有的Route必须放在里面。
Route是规则,表示渲染对应的组件。
每个组件都有三个对象,history,locaiton,match

它的原理Router下的每个Route都有三个对象,是采用context的做法。

实现基本路由

路由库其实有三个库

react-router-dom依赖react-router,react-router依赖History。react-router是所有平太共享的,react-router-dom是浏览器专属的。
实现原理:
其实实现原理很容易理解,Router是容器,他们传值是通过React.createContext。比如

在Router容器中间还有一层provider,借助他来进行值的传递。然后Router内部,会根据Loaction.path来获取当前浏览器的地址,并且跟Route的path做比对,一旦Route的Path比对上了,就会去渲染component这个组件。
实现原理就是这样。
我们基于这个原理既可以实现我们自己的react-router。

Router的实现


定义一个context上下文。

然后Router的实现就是包罗了一层Provider,location,history是从父组件传入的,哪里呢?

就是react-router-dom中的HashRouter,他会通过history这个库,创建一个History对象,这个history不是window.history。然后将History传入给Router,这样Router就可以拿到history对象了。注意我们监听了History的Listen方法,当路劲变化的时候就会触发这个方法。
这样Router就实现完毕了,是不是很简单。

Route的实现


Route的实现思路就是

  • 通过Context获取Location和history,判断Props.path是不是跟当前的路劲一样,不是的话渲染null,是的话渲染component属性。
  • 地址变化会触发我们在Router设定的listen方法,获取最新的location,然后重新渲染组件。到Route的时候继续做判断是否渲染即可。

BrowerRouter的实现

history路由的实现跟hash路由一样,
只不过创建的历史对象变成了createBrowerHistory而已。
让我们看看效果:



实现完毕。

总结

首先就是通过history这个库获取创建history对象的方法,再将history传入给Router,Router拿到这个方法后做一个监听,history.listen,他会监听地址的变化,然后重新渲染组件,将history以及Location作为context的value传下去。Route组件是包裹在Router下的,所以可以通过contextType拿到locaiton,再根据Location的pathname跟自己的Porps的Path比对,判断是否渲染component。

history库的实现

接着实现createHashRouter, createBrowserRouter的方法

createBrowserRouter

createBrowserRouter是一个工厂方法,用来返回history这个对象。

返回history。接着来实现里面的方法。go goBack goForward三个window.history都有实现,所以可以使用柯里化的函数形式来

接着是listen。listen是用来加入监听者的,当路劲改变的时候再告诉每个监听者。
通过数组存放监听者。
push方法的实现

pushState会改变当前的地址,但不会引起页面改变。所以下面接着对History的location进行更新,然后告诉监听者,路劲改变了,传入最新的Location。对应到上面我们的Router的listen监听的时候,会重新渲染组件,拿到最新的location,再去匹配对应的Route
这也是实现思路,前端框架监听路由的变化去实现不同组件的渲染。
效果:



createHashRouter的实现

因为hash没有像window.history这种,所以我们必须自己实现一个类似的历史条目栈,索引等等。实现的原理就是通过读写window.loction.hash然后监听hashchange去调用函数,更新History对象,渲染不同的组件。

先实现go,hash没有window.history.go,所以们得自己实现,
思路就是通过自己封装的历史条目站,通过索引拿到Location,重新写hash值去触发onhashChange。

先更新history这个对象,因为需要放入到栈中的。然后通知监听者改变。

push直接改变hash值就好,因为会触发OnhsahCHange在那边做处理。

listener跟createbrowserHistory一样。这样我们的createHashHIstory就实现完了。看效果:


正常实现。

总结:

先了解了history的原理和hash的原理,hash就是通过读写hash值,然后通过监听hashChange去渲染不同的组件。而history是通过window.history这个对象,通过go goBack这些实现基本的方法,通过监听popState去渲染不同的组件。通过pushState去完成Push方法,改变了地址后,然后执行监听函数,通知监听者改变。
Router的实现,基本就是通过React.context的借助history这个对象的一个高阶组件。在这个组件中去监听history的Listen方法,再重新触发组件更新,更新history,location值。然后Route就是通过context以及path component去匹配渲染对应的组件。
react-router-dom的HashRouter和BrowserRouter的主要目的就是创建history对象,并且将值传入Router组件。

以上是关于ZF_react react-router起步 React路由原理 简单实现Router Route createHashRouter createBrowserRouter。的主要内容,如果未能解决你的问题,请参考以下文章

ZF_react react-router 使用正则匹配路由,Switch路由,嵌套路由的实现 路由保护 NavLink withRouter

ZF_react ref的实现 生命周期的实现

在react-route r中设置params的类型

ZF_react 类组件状态的使用 实现组件的更新,合成事件,批量更新

ZF_react hooks useState的实现 useCallback useMemo useReducer useContext

ZF_react dom-diff 新的生命周期,context上下文实现