深入理解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延迟加载
Mar 09 Javascript
js静态方法与实例方法分析
Jul 04 Javascript
用js来获取上传的文件名纯粹是为了美化而用
Oct 23 Javascript
按Enter键触发事件的jquery方法实现代码
Feb 17 Javascript
Javascript将数值转换为金额格式(分隔千分位和自动增加小数点)
Jun 22 Javascript
jQuery实现下拉框多选 jquery-multiselect 的实例代码
Jul 14 Javascript
JavaScript原生数组Array常用方法
Apr 06 Javascript
Easy UI动态树点击文字实现展开关闭功能
Sep 30 Javascript
mac上配置Android环境变量的方法
Jul 08 Javascript
JS实现把一个页面层数据传递到另一个页面的两种方式
Aug 13 Javascript
vue进入页面时滚动条始终在底部代码实例
Mar 26 Javascript
js实现计时器秒表功能
Dec 16 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 number_format() 函数定义和用法
2012/06/01 PHP
Codeigniter校验ip地址的方法
2015/03/21 PHP
php生成0~1随机小数的方法(必看)
2017/04/05 PHP
php实现通过stomp协议连接ActiveMQ操作示例
2020/02/23 PHP
Ext.MessageBox工具类简介
2009/12/10 Javascript
基于JavaScript实现继承机制之构造函数方法对象冒充的使用详解
2013/05/07 Javascript
JavaScript Array对象扩展indexOf()方法
2014/05/09 Javascript
详解JavaScript中的异常处理方法
2015/06/16 Javascript
JAVA四种基本排序方法实例总结
2015/07/24 Javascript
AngularJS入门教程之AngularJS模型
2016/04/18 Javascript
第九章之路径分页标签与徽章组件
2016/04/25 Javascript
Bootstrap编写导航栏和登陆框
2016/05/30 Javascript
利用select实现年月日三级联动的日期选择效果【推荐】
2016/12/13 Javascript
使用Bootstrap + Vue.js实现添加删除数据示例
2017/02/27 Javascript
详解Angular4中路由Router类的跳转navigate
2017/06/09 Javascript
jQuery实现返回顶部按钮和scroll滚动功能[带动画效果]
2017/07/05 jQuery
JavaScript常用数学函数用法示例
2018/05/14 Javascript
微信小程序实现蒙版弹窗效果
2018/11/01 Javascript
javascript实现一款好看的秒表计时器
2020/09/05 Javascript
JavaScript实现弹出窗口效果
2020/12/09 Javascript
CentOS6.5设置Django开发环境
2016/10/13 Python
Ubuntu安装Jupyter Notebook教程
2017/10/18 Python
Python with语句上下文管理器两种实现方法分析
2018/02/09 Python
对numpy Array [: ,] 的取值方法详解
2018/07/02 Python
Pytorch 抽取vgg各层并进行定制化处理的方法
2019/08/20 Python
django重新生成数据库中的某张表方法
2019/08/28 Python
Pytorch Tensor 输出为txt和mat格式方式
2020/01/03 Python
深入理解Tensorflow中的masking和padding
2020/02/24 Python
利用python绘制中国地图(含省界、河流等)
2020/09/21 Python
css3实现顶部社会化分享按钮示例
2014/05/06 HTML / CSS
证婚人经典证婚词
2014/01/09 职场文书
工会主席岗位责任制
2014/02/11 职场文书
县委务虚会发言材料
2014/10/20 职场文书
2015年社区综治工作总结
2015/04/21 职场文书
党员转正党支部意见
2015/06/02 职场文书
python使用XPath解析数据爬取起点小说网数据
2021/04/22 Python