深入理解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 相关文章推荐
不同浏览器的怪癖小结
Jul 11 Javascript
nullJavascript中创建对象的五种方法实例
May 07 Javascript
javascript阻止scroll事件多次执行的思路及实现
Nov 08 Javascript
jquery使用jquery.zclip插件复制对象的实例教程
Dec 04 Javascript
减少访问DOM的次数提升javascript性能
Feb 24 Javascript
JavaScript判断浏览器对CSS3属性是否支持的多种方法
Nov 13 Javascript
jQuery中DOM节点的删除方法总结(超全面)
Jan 22 Javascript
vue实现未登录跳转到登录页面的方法
Jul 17 Javascript
Vue组件教程之Toast(Vue.extend 方式)详解
Jan 27 Javascript
微信小程序实现获取小程序码和二维码java接口开发
Mar 29 Javascript
vue 获取视频时长的实例代码
Aug 20 Javascript
vue 解决异步数据更新问题
Oct 29 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 管理系统程序中的后门
2009/08/05 PHP
php导入csv文件碰到乱码问题的解决方法
2014/02/10 PHP
IIS下PHP的三种配置方式对比
2014/11/20 PHP
ThinkPHP 404页面的设置方法
2015/01/14 PHP
js 未结束的字符串常量错误解决方法
2010/06/13 Javascript
jquery随机展示头像代码
2011/12/21 Javascript
javascript生成json数据简单示例分享
2014/02/14 Javascript
JS基于FileSystemObject创建一个指定路径的TXT文本文件
2015/08/05 Javascript
Javascript实现代码折叠功能
2016/08/25 Javascript
js实现导航栏中英文切换效果
2017/01/16 Javascript
Angular.js中$resource高大上的数据交互详解
2017/07/30 Javascript
搭建element-ui的Vue前端工程操作实例
2018/02/23 Javascript
vue-cli+webpack项目 修改项目名称的方法
2018/02/28 Javascript
p5.js入门教程之键盘交互
2018/03/19 Javascript
微信小程序实现发红包功能
2018/07/11 Javascript
使用webpack构建应用的方法步骤
2019/03/04 Javascript
让你30分钟快速掌握vue3教程
2020/10/26 Javascript
8个非常实用的Vue自定义指令
2020/12/15 Vue.js
教大家玩转Python字符串处理的七种技巧
2017/03/31 Python
浅谈python中requests模块导入的问题
2018/05/18 Python
解决已经安装requests,却依然提示No module named requests问题
2018/05/18 Python
Pycharm之快速定位到某行快捷键的方法
2019/01/20 Python
django fernet fields字段加密实践详解
2019/08/12 Python
python颜色随机生成器的实例代码
2020/01/10 Python
Python日志器使用方法及原理解析
2020/09/27 Python
mac系统下安装pycharm、永久激活、中文汉化详细教程
2020/11/24 Python
大整数数相乘的问题
2012/07/22 面试题
自我鉴定四大框架
2014/01/17 职场文书
交通安全寄语大全
2014/04/08 职场文书
事业单位鉴定材料
2014/05/25 职场文书
企业介绍信范文
2015/01/30 职场文书
义卖募捐活动总结
2015/05/09 职场文书
小学生反邪教心得体会
2016/01/15 职场文书
Linux安装Nginx步骤详解
2021/03/31 Servers
MySQL高速缓存启动方法及参数详解(query_cache_size)
2021/07/01 MySQL
Redis实现分布式锁的五种方法详解
2022/06/14 Redis