深入理解react-router 路由的实现原理


Posted in Javascript onSeptember 26, 2018

React Router 是一个基于 React 之上的强大路由库,它可以让你向应用中快速地添加视图和数据流,同时保持页面与 URL 间的同步。本文从两个方便来解析 react-router 实现原理。一:介绍 react-router 的依赖库history;二:使用 history 库,实现一个简单的 react-router 路由。

history 介绍

history 是一个 JavaScript 库,可让您在 JavaScript 运行的任何地方轻松管理会话历史记录。history 抽象出各种环境中的差异,并提供最小的 API ,使您可以管理历史堆栈,导航,确认导航以及在会话之间保持状态。

history 有三种实现方式:

1、BrowserHistory:用于支持 HTML5 历史记录 API 的现代 Web 浏览器(请参阅跨浏览器兼容性)
2、HashHistory:用于旧版Web浏览器
3、MemoryHistory:用作参考实现,也可用于非 DOM 环境,如 React Native 或测试

三种实现方法,都是创建了一个 history 对象,这里主要讲下前面两种:

const history = {
 length: globalHistory.length, 
 action: "POP", 
 location: initialLocation,
 createHref,
 push, // 改变location
 replace,
 go,
 goBack,
 goForward,
 block,
 listen //监听路由变化
};

1.页面跳转实现

BrowserHistory:pushState、replaceState;

HashHistory:location.hash、location.replace

function push(){
 createKey(); // 创建location的key,用于唯一标示该location,是随机生成的
 if(BrowserHistory){
 globalHistory.pushState({ key, state }, null, href);
 }else if(HashHistory){
 window.location.hash = path;
 }
 //上报listener 更新state ...
}
function replace(){
 createKey(); // 创建location的key,用于唯一标示该location,是随机生成的
 if(BrowserHistory){
 globalHistory.replaceState({ key, state }, null, href); 
 }else if(HashHistory){
 window.location.replace(window.location.href.slice(0, hashIndex >= 0 ? hashIndex : 0) + "#" path);
 } 
 //上报listener 更新state ... 
}

2.浏览器回退

BrowserHistory:popstate;

HashHistory:hashchang;

if(BrowserHistory){
 window.addEventListener("popstate", routerChange);
}else if(HashHistory){
 window.addEventListener("hashchange", routerChange);
}
function routerChange(){
 const location = getDOMLocation(); //获取location
 //路由切换
 transitionManager.confirmTransitionTo(location,callback=()=>{
 //上报listener
 transitionManager.notifyListeners();
 });
}

通过 history 实现简单 react-router

import { Component } from 'react';
import createHistory from 'history/createHashHistory';
const history = createHistory(); //创建 history 对象
/**
 * 配置路由表
 * @type {{"/": string}}
 */
const router = {
 '/': 'page/home/index',
 '/my': 'page/my/index'
}
export default class Router extends Component {
 state = { page: null }

 async route(location) {
 let pathname = location.pathname;
 let pagePath = router[pathname];
 // 加 ./的原因 https://webpack.docschina.org/api/module-methods#import-
 const Page = await import(`./${pagePath}`); //获取路由对应的ui
 //设置ui
 this.setState({ 
  Page: Page.default 
 });
 }

 initListener(){
 //监听路由切换
 history.listen((location, action) => {
  //切换路由后,更新ui
  this.route(location);
 });
 }

 componentDidMount() {
 this.route(history.location);
 this.initListener();
 }

 render() {
 const { Page } = this.state;
 return Page && <Page {...this.props} />;
 }
}

目前react-router在项目中已有大量实践,其优点可以总结如下:

风格: 与React融为一体,专为react量身打造,编码风格与react保持一致,例如路由的配置可以通过component来实现

简单: 不需要手工维护路由state,使代码变得简单

强大: 强大的路由管理机制,体现在如下方面

  • 路由配置: 可以通过组件、配置对象来进行路由的配置
  • 路由切换: 可以通过<Link> Redirect进行路由的切换
  • 路由加载: 可以同步记载,也可以异步加载,这样就可以实现按需加载

使用方式: 不仅可以在浏览器端的使用,而且可以在服务器端的使用

当然react-router的缺点就是API不太稳定,在升级版本的时候需要进行代码变动。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
基于jQuery的倒计时插件代码
May 07 Javascript
JS获得QQ号码的昵称,头像,生日的简单实例
Dec 04 Javascript
node.js中的http.response.removeHeader方法使用说明
Dec 14 Javascript
原生JS实现平滑回到顶部组件
Mar 16 Javascript
jquery 抽奖小程序实现代码
Oct 12 Javascript
js使用highlight.js高亮你的代码
Aug 18 Javascript
jquery写出PC端轮播图实例
Jan 26 jQuery
Vue2.0 实现单选互斥的方法
Apr 13 Javascript
Vue中对拿到的数据进行A-Z排序的实例
Sep 25 Javascript
Vue+axios+WebApi+NPOI导出Excel文件实例方法
Jun 05 Javascript
wx-charts 微信小程序图表插件的具体使用
Aug 18 Javascript
Vue分页插件的前后端配置与使用
Oct 09 Javascript
node.js使用redis储存session的方法
Sep 26 #Javascript
详解Axios统一错误处理与后置
Sep 26 #Javascript
Vue监听一个数组id是否与另一个数组id相同的方法
Sep 26 #Javascript
vue 循环加载数据并获取第一条记录的方法
Sep 26 #Javascript
基于vue v-for 多层循环嵌套获取行数的方法
Sep 26 #Javascript
VUE v-for循环中每个item节点动态绑定不同函数的实例
Sep 26 #Javascript
原生JS实现简单的无缝自动轮播效果
Sep 26 #Javascript
You might like
PHP脚本的10个技巧(7)
2006/10/09 PHP
php下保存远程图片到本地的办法
2010/08/08 PHP
PHP数据库链接类(PDO+Access)实例分享
2013/12/05 PHP
php中cookie的使用方法
2014/03/29 PHP
在Laravel框架里实现发送邮件实例(邮箱验证)
2016/05/20 PHP
php实现数组重复数字统计实例
2018/09/30 PHP
js关于字符长度限制的问题示例探讨
2014/01/24 Javascript
nodejs调用cmd命令实现复制目录
2015/05/04 NodeJs
jQuery+Ajax+PHP弹出层异步登录效果(附源码下载)
2016/05/27 Javascript
BootStrap智能表单实战系列(六)表单编辑页面的数据绑定
2016/06/13 Javascript
教你JS中的运算符乘方、开方及变量格式转换
2016/08/09 Javascript
如何提高数据访问速度
2016/12/26 Javascript
完美解决UI-Grid表格元素中多个空格显示为一个空格的问题
2017/04/25 Javascript
使用jQuery实现简单的tab框实例
2017/08/22 jQuery
Vue.JS实现垂直方向展开、收缩不定高度模块的JS组件
2018/06/19 Javascript
基于vue-cli搭建多模块且各模块独立打包的项目
2019/06/12 Javascript
mpvue 项目初始化及实现授权登录的实现方法
2020/07/20 Javascript
[09:33]2015国际邀请赛第四日TOP10
2015/08/08 DOTA
[01:27:44]DOTA2-DPC中国联赛 正赛 PSG.LGD vs Aster BO3 第一场 1月24日
2021/03/11 DOTA
python批量同步web服务器代码核心程序
2014/09/01 Python
发布你的Python模块详解
2016/09/15 Python
python实现傅里叶级数展开的实现
2018/07/21 Python
对django后台admin下拉框进行过滤的实例
2019/07/26 Python
python__name__原理及用法详解
2019/11/02 Python
如何通过Django使用本地css/js文件
2020/01/20 Python
Python unittest框架操作实例解析
2020/04/13 Python
Vans澳大利亚官网:购买鞋子、服装及配件
2019/09/05 全球购物
一道SQL存储过程面试题
2016/10/07 面试题
俞敏洪励志演讲稿
2014/04/29 职场文书
出国留学担保书
2014/05/20 职场文书
机械工程及其自动化专业求职信
2014/08/08 职场文书
解除劳动合同证明书模板
2014/11/20 职场文书
2015年健康教育工作总结
2015/04/10 职场文书
ObjectMapper 如何忽略字段大小写
2021/06/29 Java/Android
Redis中key的过期删除策略和内存淘汰机制
2022/04/12 Redis
instantclient客户端 连接oracle数据库
2022/04/26 Oracle