深入理解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+canvas实现简单的球体斜抛及颜色动态变换效果
Jan 28 Javascript
JavaScript实现时间倒计时跳转(推荐)
Jun 28 Javascript
AngularJS 过滤器的简单实例
Jul 27 Javascript
js控制li的隐藏和显示实例代码
Oct 15 Javascript
轻松理解JavaScript闭包
Mar 14 Javascript
JS检测数组类型的方法小结
Mar 14 Javascript
jQuery+ThinkPHP+Ajax实现即时消息提醒功能实例代码
Mar 21 jQuery
js中的数组对象排序分析
Dec 11 Javascript
详解element-ui日期时间选择器的日期格式化问题
Apr 08 Javascript
JavaScript自动生成 年月范围 选择功能完整示例【基于jQuery插件】
Sep 03 jQuery
BootStrap前端框架使用方法详解
Feb 26 Javascript
基于Vant UI框架实现时间段选择器
Dec 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
第一个无线电台是由谁发明的
2021/03/01 无线电
dedecms模板标签代码官方参考
2007/03/17 PHP
PHP生成UTF8文件的方法
2010/05/15 PHP
解析Win7 XAMPP apache无法启动的问题
2013/06/26 PHP
初识ThinkPHP控制器
2016/04/07 PHP
php mysql PDO 查询操作的实例详解
2017/09/23 PHP
Javascript开发之三数组对象实例介绍
2012/11/12 Javascript
js获取GridView中行数据的两种方法 分享
2013/07/13 Javascript
深入理解Javascript动态方法调用与参数修改的问题
2013/12/10 Javascript
jquery 实现两级导航菜单附效果图
2014/03/07 Javascript
jQuery给多个不同元素添加class样式的方法
2015/03/26 Javascript
asp.net+jquery.form实现图片异步上传的方法(附jquery.form.js下载)
2016/05/05 Javascript
原生javascript实现图片放大镜效果
2017/01/18 Javascript
微信小程序 Toast自定义实例详解
2017/01/20 Javascript
Angular2的管道Pipe的使用方法
2017/11/07 Javascript
vue在手机中通过本机IP地址访问webApp的方法
2018/08/15 Javascript
Vuejs+vue-router打包+Nginx配置的实例
2018/09/20 Javascript
Bootstrap的aria-label和aria-labelledby属性实例详解
2018/11/02 Javascript
React精髓!一篇全概括小结(急速)
2019/05/23 Javascript
npx create-react-app xxx创建项目报错的解决办法
2020/02/17 Javascript
浅谈Vue使用Elementui修改默认的最快方法
2020/12/05 Vue.js
python的几种开发工具介绍
2007/03/07 Python
css3 矩阵的使用详解
2018/03/20 HTML / CSS
canvas使用注意点总结
2013/07/19 HTML / CSS
ProBikeKit新西兰:自行车套件,跑步和铁人三项装备
2017/04/05 全球购物
Expedia丹麦:全球领先的旅游网站
2018/03/18 全球购物
五一服装活动方案
2014/01/11 职场文书
素食餐饮项目创业计划书
2014/02/02 职场文书
教师求职信
2014/06/17 职场文书
四风问题查摆材料
2014/08/25 职场文书
教师群众路线教育实践活动学习笔记
2014/11/05 职场文书
2015年党员个人自我评价
2015/03/03 职场文书
通知范文怎么写
2015/04/16 职场文书
JS的深浅复制详细
2021/10/16 Javascript
Vue的生命周期一起来看看
2022/02/24 Vue.js
Linux中如何安装并部署Redis
2022/04/18 Servers