深入理解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的高性能td和input切换并可修改内容实现代码
Jan 09 Javascript
客户端js判断文件类型和文件大小即限制上传大小
Nov 20 Javascript
JavaScript判断变量是对象还是数组的方法
Aug 28 Javascript
AngularJS基础教程之简单介绍
Sep 27 Javascript
javascript中select下拉框的用法总结
Jan 07 Javascript
鼠标拖动改变DIV等网页元素的大小的实现方法
Jul 06 Javascript
angular4模块中给标签添加背景图的实现方法
Sep 15 Javascript
详解使用angular框架离线你的应用(pwa指南)
Jan 31 Javascript
Vue实现导航栏点击当前标签变色功能
Aug 19 Javascript
Vue的Eslint配置文件eslintrc.js说明与规则介绍
Feb 03 Javascript
微信小程序实现菜单左右联动
May 19 Javascript
vue实现评价星星功能
Jun 30 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的header和asp中的redirect比较
2006/10/09 PHP
php自动跳转中英文页面
2008/07/29 PHP
PHP导出带样式的Excel示例代码
2016/08/28 PHP
PHP实现通过strace定位故障原因的方法
2018/04/29 PHP
PHP+mysql实现的三级联动菜单功能示例
2019/02/15 PHP
php实现的表单验证类完整示例
2019/08/13 PHP
excel操作之Add Data to a Spreadsheet Cell
2007/06/12 Javascript
js和as的稳定传值问题解决
2013/07/14 Javascript
ExtJs中gridpanel分组后组名排序实例代码
2013/12/02 Javascript
JavaScript中反正弦函数Math.asin()的使用简介
2015/06/14 Javascript
jquery.cookie.js实现用户登录保存密码功能的方法
2016/04/15 Javascript
jQuery中的select操作详解
2016/11/29 Javascript
深入理解jquery中extend的实现
2016/12/22 Javascript
Angular 4.x中表单Reactive Forms详解
2017/04/25 Javascript
总结JavaScript在IE9之前版本中内存泄露问题
2018/04/28 Javascript
浅析vue中的provide / inject 有什么用处
2019/11/10 Javascript
结合axios对项目中的api请求进行封装操作
2020/09/21 Javascript
python小技巧之批量抓取美女图片
2014/06/06 Python
python如何在终端里面显示一张图片
2016/08/17 Python
Python排序搜索基本算法之插入排序实例分析
2017/12/11 Python
利用TensorFlow训练简单的二分类神经网络模型的方法
2018/03/05 Python
对numpy中数组元素的统一赋值实例
2018/04/04 Python
Python 使用PIL numpy 实现拼接图片的示例
2018/05/08 Python
wxPython窗体拆分布局基础组件
2019/11/19 Python
Python中如何将一个类方法变为多个方法
2019/12/30 Python
css3实例教程 一款纯css3实现的发光屏幕旋转特效
2014/12/07 HTML / CSS
css3实现蒙版弹幕功能
2019/06/18 HTML / CSS
html5 button autofocus 属性介绍及应用
2013/01/04 HTML / CSS
新西兰最大的品牌运动鞋购物网站:Platypus NZ
2017/10/27 全球购物
理工大学毕业生自荐信
2013/11/01 职场文书
上课看小说检讨书
2014/02/22 职场文书
初三新学期计划书
2014/05/03 职场文书
企业理念标语
2014/06/09 职场文书
大学团日活动总结书
2015/05/11 职场文书
民事答辩状范本
2015/05/21 职场文书
在CSS中使用when/else的方法
2022/01/18 HTML / CSS