记React-router原理探索

231 阅读3分钟

react-router

基本使用(配合react-redux用路由守卫写一个登录)

点击用户中心若登陆正常显示,若未登录跳转登录页,登录页登录成功后跳转回原页面。若直接url到登录页,登陆成功后默认跳转回首页。

store.js & index.js

App.js

PrivateRoute

Login

User

BrowserRouter

使⽤HTML5提供的history API(pushState , replaceState 和 popstate 事件)

HashRouter

HashRouter 使⽤URL的hash值(即window.location.hash)

官方提示注意:hash history 不⽀持 location.key 和location.state。在以前的版本中,我们曾尝试 shim这种⾏为,但是仍有⼀些边缘问题⽆法解决。因此任何依赖此⾏为的代码或插件都将⽆法正常使⽤。由于该技术仅⽤于⽀持旧浏览器,因此我们⿎励⼤家使⽤BrowserHistory。

BrowserRouter 和 HashRouter区别

  1. HashRouter简单,不需要服务器端渲染,靠浏览器的#来区分路径即可,BrowserRouter需要服务器端对不同的URL返回不同的HTML,后端配置可参考。如果服务器是nginx其实就是配置try_files

  2. BrowserRouter使⽤HTML5 history API , HashRouter 使用URL的hash值

  3. HashRouter不⽀持location.key和location.state,动态路由跳转需要通过?传递参数。

  4. 官方提示:Hash history 不需要服务器任何配置就可以运⾏,如果你刚刚⼊⻔,那就使⽤它吧。但是我们不推荐在实际线上环境中⽤到它,因为每⼀个web 应⽤都应该渴望使⽤browserHistory。

实现

App.js 首先实现BrowserRouter Link Route

image.png

BrowserRouter

image.png

BrowserRouter很简单就是显示插槽中的组件内容。

Link

image.png

  • Link首先能接收to和children,接着返回一个a标签。

Route

image.png

Route首先能接收path和component,根据路径比对渲染对应的页面。

现在基本实现点击切换路由显示对应页面,但是切换的时候存在闪烁的现象,这就是a标签的原生态了。进一步修改Link。

image.png

此时点击切换不会再闪烁 但是点击事件也被禁止了。我们需要引入history让编程式导航去推动。history从哪来,在BrowserRouter通过context注入进来。

首先创建context/react-router-context

image.png

修改BrowserRouter.js使用context把创建的history注入

image.png

修改Link.js接收到history使用history.push完成编程式导航

image.png

此时点击切换路径无问题而页面还未跟着切换渲染,想法是Provider value值发生变动当前的组件是会被重新渲染的,所以可以监听location的变化达到组件重新渲染的目的。

  • 修改BrowserRouter.js 使用history.listen监听location改变触发setState,使用context把创建的loaction注入

image.png

修改Route.js接收context

image.png

修改BrowserRouter.js 组件卸载时销毁监听

image.png

实现component children render三大渲染形式

对于component通过简单的React.createElement(component,props)搞定了

修改下App.js

image.png

修改Route.js

首先要知道路由渲染后的组件的this.props有啥有history 有location 有match:

image.png

所以在创建组件时需要把这些传下去。

紧接着就是三元逻辑判断:

match 匹配成功渲染children, component, render 或者 null

match 匹配成功渲染children两种情况 1.children为function 2.children本身也就是节点

match 匹配不成功渲染children 或者 null

children和location无关所以children和匹配无关 不管有没有匹配都会渲染

image.png

此时动态路由与嵌套路由也能正常执行

image.png

由于嵌套最里层的肯定要匹配最近一层的,也就是下一级肯定是拿到上一级传递的props而不是一开始注入的props 修改Route.js

image.png

Switch

App.js

image.png

Switch.js

image.png

对于Switch还可以传loaction参数(无论切换任何路由都只显示location设置的路由)

App.js

image.png

Switch.js

image.png

对于404 没有path现在返回的上下文是BrowserRouter的match 而BrowserRouter没有传match 所以match为undefined,最终返回了null而没有显示404页面。所以在BrowserRouter初始化一个match

修改BrowserRouter.js

image.png

此时match就不是undefined了执行React.cloneElement(element, {location})

到了Route.js

image.png

修改Switch.js

image.png

修改Route.js

image.png

Redirect(这里就用之前写的路由守卫做测试了)

App.js

image.png

PrivateRoute

image.png

Redirect.js

image.png