深入理解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 相关文章推荐
JAVASCRIPT HashTable
Jan 22 Javascript
JavaScript语法着色引擎(demo及打包文件下载)
Jun 13 Javascript
javascript下过滤数组重复值的代码
Sep 10 Javascript
javascript写的日历类(基于pj)
Dec 28 Javascript
JQuery触发radio或checkbox的change事件
Dec 18 Javascript
热点新闻滚动特效的js代码
Aug 17 Javascript
Javascript访问器属性实例分析
Dec 30 Javascript
jQuery解析XML与传统JavaScript方法的差别实例分析
Mar 05 Javascript
AngularJS 过滤器的简单实例
Jul 27 Javascript
js实现无缝滚动图(可控制当前滚动的方向)
Feb 22 Javascript
Linux系统中利用node.js提取Word(doc/docx)及PDF文本的内容
Jun 17 Javascript
微信小程序实现手指触摸画板
Jul 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正则的Unknown Modifier错误解决方法
2010/03/02 PHP
基于PHPExcel的常用方法总结
2013/06/13 PHP
destoon利用Rewrite规则设置网站安全
2014/06/21 PHP
分享10段PHP常用代码
2015/11/11 PHP
46 个非常有用的 PHP 代码片段
2016/02/16 PHP
实例讲解PHP设计模式编程中的简单工厂模式
2016/02/29 PHP
PHP中功能强大却很少使用的函数实例小结
2016/11/10 PHP
php生成图片缩略图功能示例
2017/02/22 PHP
PHP实现百度人脸识别
2019/05/06 PHP
wordpress之js库集合研究介绍
2007/08/17 Javascript
Jquery知识点三 jquery表单对象操作
2011/01/17 Javascript
基于jquery的多彩百分比 动态进度条 投票效果显示效果实现代码
2011/08/28 Javascript
Knockoutjs的环境搭建教程
2012/11/26 Javascript
jQuery删除一个元素后淡出效果展示删除过程的方法
2015/03/18 Javascript
简介JavaScript中setUTCSeconds()方法的使用
2015/06/12 Javascript
用file标签实现多图文件上传预览
2017/02/14 Javascript
JavaScript 数组去重并统计重复元素出现的次数实例
2017/12/14 Javascript
node.js环境搭建图文详解
2018/09/19 Javascript
在微信小程序中使用图表的方法示例
2019/04/25 Javascript
前端路由&amp;webpack基础配置详解
2019/06/10 Javascript
如何使用Node.js爬取任意网页资源并输出PDF文件到本地
2019/06/17 Javascript
[45:25]OG vs EG 2019国际邀请赛淘汰赛 胜者组 BO3 第一场 8.22
2019/09/05 DOTA
python覆盖写入,追加写入的实例
2019/06/26 Python
Python帮你微信头像任意添加装饰别再@微信官方了
2019/09/25 Python
python基于FTP实现文件传输相关功能代码实例
2019/09/28 Python
在pytorch中实现只让指定变量向后传播梯度
2020/02/29 Python
python实现文法左递归的消除方法
2020/05/22 Python
Python如何在windows环境安装pip及rarfile
2020/06/15 Python
python获取整个网页源码的方法
2020/08/03 Python
html5使用Canvas绘图的使用方法
2017/11/21 HTML / CSS
Bally澳大利亚官网:瑞士奢侈品牌
2018/11/01 全球购物
JD Sports澳洲官网:英国领先的运动鞋和运动时尚零售商
2020/02/15 全球购物
小学生演讲稿
2014/01/12 职场文书
教师专业自荐信
2014/05/31 职场文书
三提三创主题教育活动查摆整改措施
2014/10/25 职场文书
2015年保育员个人工作总结
2015/05/13 职场文书