深入理解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 相关文章推荐
showModalDialog模态对话框的使用详解以及浏览器兼容
Jan 11 Javascript
JavaScript常用脚本汇总(一)
Mar 04 Javascript
node.js cookie-parser之parser.js
Jun 06 Javascript
Vue.js中关于侦听器(watch)的高级用法示例
May 02 Javascript
小程序分享模块超级详解(推荐)
Apr 10 Javascript
websocket4.0+typescript 实现热更新的方法
Aug 14 Javascript
Vue中fragment.js使用方法小结
Feb 17 Javascript
js实现烟花特效
Mar 02 Javascript
Vue的全局过滤器和私有过滤器的实现
Apr 20 Javascript
基于JS实现计算24点算法代码实例解析
Jul 23 Javascript
JavaScript实现网页tab栏效果制作
Nov 20 Javascript
element多个表单校验的实现
May 27 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
PHP5 面向对象程序设计
2008/02/13 PHP
php中通过curl模拟登陆discuz论坛的实现代码
2012/02/16 PHP
PHP gbk环境下json_dencode传送来的汉字
2012/11/13 PHP
PHP静态文件生成类实例
2014/11/29 PHP
PHP中让curl支持sock5的代码实例
2015/01/21 PHP
PHP结合Mysql数据库实现留言板功能
2016/03/04 PHP
Laravel模糊查询区分大小写的实例
2019/09/29 PHP
浅谈laravel 5.6 安装 windows上使用composer的安装过程
2019/10/18 PHP
jQuery 1.2.x 升? 1.3.x 注意事项
2009/05/06 Javascript
ext checkboxgroup 回填数据解决
2009/08/21 Javascript
js 异步操作回调函数如何控制执行顺序
2013/12/24 Javascript
JS操作CSS随机改变网页背景实现思路
2014/03/10 Javascript
js+html5获取用户地理位置信息并在Google地图上显示的方法
2015/06/05 Javascript
jquery validate和jquery form 插件组合实现验证表单后AJAX提交
2015/08/26 Javascript
温习Javascript基础语法之词法结构
2016/05/31 Javascript
JS如何判断json是否为空
2016/07/06 Javascript
AngularJs bootstrap搭载前台框架——准备工作
2016/09/01 Javascript
jQuery视差滚动效果网页实现方法经验总结
2016/09/29 Javascript
vue 实现剪裁图片并上传服务器功能
2018/03/01 Javascript
layer弹出层自定义提交取消按钮的例子
2019/09/10 Javascript
Nuxt v-bind绑定img src不显示的解决
2019/12/05 Javascript
[03:12]完美世界DOTA2联赛PWL DAY9集锦
2020/11/10 DOTA
Python 实现淘宝秒杀的示例代码
2018/01/02 Python
详解Python自建logging模块
2018/01/29 Python
pytorch动态网络以及权重共享实例
2020/01/06 Python
Python中os模块功能与用法详解
2020/02/26 Python
HTML5移动端开发遇见的东西
2019/10/11 HTML / CSS
台湾旅游网站:雄狮旅游网
2017/08/16 全球购物
意大利自行车商店:Cingolani Bike Shop
2019/09/03 全球购物
什么是规则表达式
2012/05/03 面试题
施工安全协议书
2013/12/11 职场文书
导游个人求职信范文
2014/03/23 职场文书
学校文明单位申报材料
2014/05/06 职场文书
班级活动总结格式
2014/08/30 职场文书
加强作风建设工作总结
2014/10/23 职场文书
护士岗前培训心得体会
2016/01/08 职场文书