深入理解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 相关文章推荐
JS中的public和private对象,即static修饰符
Jan 18 Javascript
兼容IE和FF的图片上传前预览js代码
May 28 Javascript
JQuery中使用ajax传输超大数据的解决方法
Jul 14 Javascript
javascript解析json实例详解
Nov 05 Javascript
jquery+正则实现统一的表单验证
Sep 20 Javascript
基于jQuery和CSS3制作数字时钟附源码下载(jquery篇)
Nov 24 Javascript
Javascript获取图片原始宽度和高度的方法详解
Sep 20 Javascript
Node.js中环境变量process.env的一些事详解
Oct 26 Javascript
Vue插件之滑动验证码用法详解
Apr 05 Javascript
使用Webpack 搭建 Vue3 开发环境过程详解
Jul 28 Javascript
Vue实现腾讯云点播视频上传功能的实现代码
Aug 17 Javascript
vue ref如何获取子组件属性值
Mar 31 Vue.js
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 Smarty date_format [格式化时间日期]
2010/03/15 PHP
php feof用来识别文件末尾字符的方法
2010/08/01 PHP
Yii CGridView用法实例详解
2016/07/12 PHP
php封装的pdo数据库操作工具类与用法示例
2019/05/08 PHP
jQuery 页面 Mask实现代码
2010/01/09 Javascript
javascript 子窗体父窗体相互传值方法
2010/05/31 Javascript
javascript与CSS复习(三)
2010/06/29 Javascript
jQuery选中select控件 无法设置selected的解决方法
2010/09/01 Javascript
仿jQuery的siblings效果的js代码
2011/08/09 Javascript
jQuery代码优化 遍历篇
2011/11/01 Javascript
javascript实现类似百度分享功能的方法
2015/07/27 Javascript
Bootstrap每天必学之导航条
2015/11/27 Javascript
jQuery与JS加载事件用法分析
2016/09/04 Javascript
详解使用vue实现tab 切换操作
2017/07/03 Javascript
angular中实现li或者某个元素点击变色的两种方法
2017/07/27 Javascript
详解angularJS+Ionic移动端图片上传的解决办法
2017/09/13 Javascript
用react-redux实现react组件之间数据共享的方法
2018/06/08 Javascript
通过实例学习React中事件节流防抖
2019/06/17 Javascript
layui实现tab的添加拒绝重复的方法
2019/09/04 Javascript
javascript删除数组元素的七个方法示例
2019/09/09 Javascript
CountUp.js实现数字滚动增值效果
2019/10/17 Javascript
学习python处理python编码问题
2011/03/13 Python
基于python绘制科赫雪花
2018/06/22 Python
对Python 两大环境管理神器 pyenv 和 virtualenv详解
2018/12/31 Python
Python实现的栈、队列、文件目录遍历操作示例
2019/05/06 Python
python代码xml转txt实例
2020/03/10 Python
django 取消csrf限制的实例
2020/03/13 Python
如何使用python的ctypes调用医保中心的dll动态库下载医保中心的账单
2020/05/24 Python
Python urllib request模块发送请求实现过程解析
2020/12/10 Python
建筑公司文秘岗位职责
2013/11/29 职场文书
2014年公司庆元旦活动方案
2014/03/05 职场文书
高中生个性发展自我评价
2015/03/09 职场文书
2016教师读书思廉心得体会
2016/01/23 职场文书
2016年小学“感恩教师”主题队日活动总结
2016/04/01 职场文书
Python爬虫之爬取某文库文档数据
2021/04/21 Python
JS前端使用canvas实现物体的点选示例
2022/08/05 Javascript