深入理解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 表单之间的数据传递代码
Dec 04 Javascript
Jquery命名冲突解决的五种方案分享
Mar 16 Javascript
谷歌showModalDialog()方法不兼容出现对话窗口的解决办法
Feb 15 Javascript
AngularJS中的包含详细介绍及实现示例
Jul 28 Javascript
js严格模式总结(分享)
Aug 22 Javascript
jquery删除table当前行的实例代码
Oct 07 Javascript
JS排序之选择排序详解
Apr 08 Javascript
你有必要知道的10个JavaScript难点
Jul 25 Javascript
Cropper.js 实现裁剪图片并上传(PC端)
Aug 20 Javascript
vue2+el-menu实现路由跳转及当前项的设置方法实例
Nov 07 Javascript
浅谈微信小程序flex布局基础
Sep 10 Javascript
微信小程序MUI导航栏透明渐变功能示例(通过改变opacity实现)
Jan 24 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读取MySQL数据代码
2008/06/05 PHP
php中curl和file_get_content的区别
2014/05/10 PHP
Yii中render和renderPartial的区别
2014/09/03 PHP
PHP中is_file()函数使用指南
2015/05/08 PHP
php准确获取文件MIME类型的方法
2015/06/17 PHP
PHP内存使用情况如何获取
2015/10/10 PHP
PHP给源代码加密的几种方法汇总(推荐)
2018/02/06 PHP
javascript 浏览器检测代码精简版
2010/03/04 Javascript
jquery 多级下拉菜单核心代码
2010/05/21 Javascript
我的javascript 函数链之演变
2011/04/07 Javascript
js传参数受特殊字符影响错误的解决方法
2013/10/21 Javascript
Windows8下搭建Node.js开发环境教程
2014/09/03 Javascript
浏览器中url存储的JavaScript实现
2015/07/07 Javascript
实例讲解JavaScript中call、apply、bind方法的异同
2016/09/13 Javascript
深入解析Vue 组件命名那些事
2017/07/18 Javascript
vue2.0使用v-for循环制作多级嵌套菜单栏
2018/06/25 Javascript
微信小程序实现图片滚动效果示例
2018/12/05 Javascript
Python操作SQLite简明教程
2014/07/10 Python
Flask框架的学习指南之制作简单blog系统
2016/11/20 Python
Python scikit-learn 做线性回归的示例代码
2017/11/01 Python
Python网络爬虫神器PyQuery的基本使用教程
2018/02/03 Python
使用Python实现文字转语音并生成wav文件的例子
2019/08/08 Python
python检测服务器端口代码实例
2019/08/31 Python
django创建超级用户过程解析
2019/09/18 Python
pandas 强制类型转换 df.astype实例
2020/04/09 Python
解决Jupyter Notebook开始菜单栏Anaconda下消失的问题
2020/04/13 Python
Python3压缩和解压缩实现代码
2021/03/01 Python
css3 按钮样式简单可扩展创建
2013/03/18 HTML / CSS
野兽派官方旗舰店:THE BEAST 野兽派
2016/08/05 全球购物
本科生导师推荐信范文
2014/05/18 职场文书
房地产销售主管岗位职责
2015/02/13 职场文书
新员工试用期自我评价
2015/03/10 职场文书
文明上网主题班会
2015/08/14 职场文书
汉语拼音教学反思
2016/02/22 职场文书
MySQL sql_mode的使用详解
2021/05/08 MySQL
Python语法学习之进程的创建与常用方法详解
2022/04/08 Python