1、hash的方式

以 hash 形式(也可以使用 History API 来处理)为例,当 url 的 hash 发生变化时,触发 hashchange 注册的回调,回调中去进行不同的操作,进行不同的内容的展示

function Router() {
this.routes = {};
this.currentUrl = '';
}
Router.prototype.route = function(path, callback) {
this.routes[path] = callback || function(){};
};
Router.prototype.refresh = function() {
this.currentUrl = location.hash.slice(1) || '/';
this.routes[this.currentUrl]();
};
Router.prototype.init = function() {
window.addEventListener('load', this.refresh.bind(this), false);
window.addEventListener('hashchange', this.refresh.bind(this), false);
}
window.Router = new Router();
window.Router.init();

link的实现

可以从 react-router/ Link 中看到,对该组件的点击事件进行了阻止了浏览器的默认跳转行为,而改用 history 模块的 pushState 方法去触发 url 更新。

为什么React组件会更新

给history注册了lisetner事件,也就是里面的setState函数;

history.push(pathname,state)函数执行,这里会执行注册的listener函数

listerer中的React的setState会执行;

React组件更新;

其实无论是react-router. react-redux. 能够使组件更新的根本原因,还是最后出发了setState函数;

对于react-router,其实是对history原生对象的封装,重新封装了push函数,使得我们在push函数执行的时候,可以触发在Router组件中组件装载之前,执行了history.listener函数,该函数的主要作用就是给listeners数组添加监听函数,每次执行history.push的时候,都会执行listenrs数组中添加的listener,这里的listener就是传入的箭头函数,功能是执行了Router组件的setState函数,从《Router Switch Route源码解析》文章中,可以看出来,Router执行了setState之后,会将当前url地址栏对应的url传递下去,当Route组件匹配到该地址栏的时候,就会渲染该组件,如果匹配不到,Route组件就返回null;

componentWillMount() {
const { children, history } = this.props invariant(
children == null || React.Children.count(children) === 1,
'A <Router> may have only one child element'
) // Do this here so we can setState when a <Redirect> changes the
// location in componentWillMount. This happens e.g. when doing
// server rendering using a <StaticRouter>.
//这里执行history.listen()方法;传入一个函数;箭头函数的this指的是父级的作用域中的this值;
this.unlisten = history.listen(() => {
this.setState({
match: this.computeMatch(history.location.pathname)
})
})
}

1、react-router依赖基础 - history

history是一个独立的第三方js库,可以用来兼容在不同浏览器、不同环境下对历史记录的管理,拥有统一的API。具体来说里面的history分为三类:

  • 老浏览器的history: 主要通过hash来实现,对应createHashHistory

  • 高版本浏览器: 通过html5里面的history,对应createBrowserHistory

  • node环境下: 主要存储在memeory里面,对应createMemoryHistory

  • createBrowserHistory: 利用HTML5里面的history

  • createHashHistory: 通过hash来存储在不同状态下的history信息

  • createMemoryHistory: 在内存中进行历史记录的存储

执行URL前进

  • createBrowserHistory: pushState、replaceState
  • createHashHistory: location.hash=*** location.replace()
  • createMemoryHistory: 在内存中进行历史记录的存储

检测URL回退

  • createBrowserHistory: popstate
  • createHashHistory: hashchange
  • createMemoryHistory: 因为是在内存中操作

2、react-router的基本原理

框架去拦截浏览器跳转,自己去同步UI组件

其中在react-router中,URL对应Location对象,而UI是由react components来决定的,这样就转变成location与components之间的同步问题

通过router声明了一份含有 path to component 的各个映射的路由表。

react-router 还提供的 Link 组件(如下),作为提供更新 url 的途径,触发 Link 后最终将通过如上面定义的路由表进行匹配,并拿到对应的 component 及 state 进行 render 渲染页面。

3、从点击 Link 到 render 对应 component ,路由中发生了什么

Router 在 react component 生命周期之组件被挂载前 componentWillMount 中使用 this.history.listen 去注册了 url 更新的回调函数。回调函数将在 url 更新时触发,回调中的 setState 起到 render 了新的 component 的作用。

Router.prototype.componentWillMount = function componentWillMount() {
// .. 省略其他
var createHistory = this.props.history; this.history = _useRoutes2['default'](createHistory)({
routes: _RouteUtils.createRoutes(routes || children),
parseQueryString: parseQueryString,
stringifyQuery: stringifyQuery
}); this._unlisten = this.history.listen(function (error, state) {
_this.setState(state, _this.props.onUpdate);
});
};

上面的 _useRoutes2 对 history 操作便是对其做一层包装,所以调用的 this.history 实际为包装以后的对象,该对象含有 _useRoutes2 中的 listen 方法,如下

function listen(listener) {
return history.listen(function (location) {
// .. 省略其他
match(location, function (error, redirectLocation, nextState) {
listener(null, nextState);
});
});
}

可看到,上面代码中,主要分为两部分

  1. 使用了 history 模块的 listen 注册了一个含有 setState 的回调函数(这样就能使用 history 模块中的机制)
  2. 回调中的 match 方法为 react-router 所特有,match 函数根据当前 location 以及前面写的 Route 路由表匹配出对应的路由子集得到新的路由状态值 state,具体实现可见 react-router/matchRoutes ,再根据 state 得到对应的 component ,最终执行了 match 中的回调 listener(null, nextState) ,即执行了 Router 中的监听回调(setState),从而更新了展示。
如何触发监听的回调函数的执行?

url 更新主要有两种方式:简单的 hash 更新或使用 history api 进行地址更新。在 react-router 中,其提供了 Link 组件,该组件能在 render 中使用,最终会表现为 a 标签,并将 Link 中的各个参数组合放它的 href 属性中。可以从 react-router/ Link 中看到,对该组件的点击事件进行了阻止了浏览器的默认跳转行为,而改用 history 模块的 pushState 方法去触发 url 更新

可以将以上 react-router 的整个包装闭环总结为
  1. 回调函数:含有能够更新 react UI 的 react setState 方法。
  2. 注册回调:在 Router componentWillMount 中使用 history.listen 注册的回调函数,最终放在 history 模块的 回调函数数组 changeListeners 中。
  3. 触发回调:Link 点击触发 history 中回调函数数组 changeListeners 的执行,从而触发原来 listen 中的 setState 方法,更新了页面

至于前进与后退的实现,是通过监听 popstate 以及 hashchange 的事件,当前进或后退 url 更新时,触发这两个事件的回调函数,回调的执行方式 Link 大致相同,最终同样更新了 UI ,这里就不再说明。

react-router 主要是利用底层 history 模块的机制,通过结合 react 的架构机制做一层包装.

router3的按需加载方式

const about = (location, cb) => {
require.ensure([], require => {
cb(null, require('../Component/about').default)
},'about')
} //配置route
<Route path="helpCenter" getComponent={about} />

react-router的原理的更多相关文章

  1. React Router 4.x 开发,这些雷区我们都帮你踩过了

    前言 在前端框架层出不穷的今天,React 以其虚拟 DOM .组件化开发思想等特性迅速占据了主流位置,成为前端开发工程师热衷的 Javascript 库.作为 React 体系中的重要组成部分:Re ...

  2. React Router API文档

    React Router API文档 一.<BrowserRouter> 使用HTML5历史记录API(pushState,replaceState和popstate事件)的<Rou ...

  3. React Router 用法

    React Router 用法 一.DEMO import React from "react"; import { HashRouter as Router, Route, Li ...

  4. React+React Router+React-Transition-Group实现页面左右滑动+滚动位置记忆

    2018年12月17日更新: 修复在qq浏览器下执行pop跳转时页面错位问题 本文的代码已封装为npm包发布:react-slide-animation-router 在React Router中,想 ...

  5. 从 React Router 谈谈路由的那些事

    React Router 是专为 React 设计的路由解决方案,在使用 React 来开发 SPA (单页应用)项目时,都会需要路由功能,而 React Router 应该是目前使用率最高的. Re ...

  6. [Redux] Filtering Redux State with React Router Params

    We will learn how adding React Router shifts the balance of responsibilities, and how the components ...

  7. [转] React Router 使用教程

    PS:react-route就是一个决定生成什么父子关系的组件,一般和layout结合起来,保证layout不行,内部的子html进行跳转 你会发现,它不是一个库,也不是一个框架,而是一个庞大的体系. ...

  8. [Redux] Navigating with React Router <Link>

    We will learn how to change the address bar using a component from React Router. In Root.js: We need ...

  9. [Redux] Adding React Router to the Project

    We will learn how to add React Router to a Redux project and make it render our root component. Inst ...

  10. React Router基础使用

    React是个技术栈,单单使用React很难构建复杂的Web应用程序,很多情况下我们需要引入其他相关的技术 React Router是React的路由库,保持相关页面部件与URL间的同步 下面就来简单 ...

随机推荐

  1. 为Visual Studio 2012添加MSDN离线帮助

    之前有网络的情况下,一直使用的都是在线的,最近又有笔记本上面有时使用时没有网络,所以就想使用下离线的MSDN包.可是找了半天,发现都是需要再次进行下载的.VS2012使用的帮助程序是HelpViewe ...

  2. 【BZOJ1216】[HNOI2003] 操作系统(堆+模拟)

    点此看题面 大致题意: 有\(n\)个任务,每个任务有4个属性:编号.到达时间.执行时间和优先级.每个单位时间,会执行一个优先级最高(若有多个优先级最高的,就先执行到达时间较早的)的任务,请你按完成的 ...

  3. 输出流缓冲的意义 何时缓冲 Stdout Buffering

    From : https://eklitzke.org/stdout-buffering 译者:李秋豪 大多数编程语言默认提供了i/o缓冲特性,因为这会使得输出更加有效率.这些缓冲功能大都是默默工作& ...

  4. javaweb基础(29)_EL表达式

    一.EL表达式简介 EL 全名为Expression Language.EL主要作用: 1.获取数据 EL表达式主要用于替换JSP页面中的脚本表达式,以从各种类型的web域 中检索java对象.获取数 ...

  5. Java代码工具箱之解析单行单列简单Excel

    1. 使用开源工具 jxl.jar 2. 功能:解析常规Excel.xls格式测试可行,xlsx未测试.Excel测试格式为常规类似table这种简单布局文件.第一行为标题,后面行为内容.代码 可正确 ...

  6. axios常见传参方式

    1:get请求 一般发送请求是这么写 axios.get('/user?id=12345&name=user') .then(function (res) { console.log(res) ...

  7. 短短几行css代码实现滚动条效果

    如何实现使用css实现滚动条效果 实现效果,运用线性渐变来实现功能 假设我们的页面被包裹在 <body> 中,可以滚动的是整个 body,给它添加这样一个从左下到到右上角的线性渐变: bo ...

  8. Nodejs NPM CNPM优雅安装install

    由于npm和cnpm都能安装组件,安装的组件有的保存在c盘用户目录的Appdata隐藏目录下,有的保存在安装node的目录下,而且安装在c盘的话,重装系统又得重新部署,甚是麻烦,所以这里提供优雅安装的 ...

  9. 利用python生成图形验证码

    validCode.py import random from io import BytesIO from PIL import Image, ImageDraw, ImageFont def ge ...

  10. Windows Server 2008 正式版下载汇总

    windows 2008是微软推出的新一代服务器专用系统版本, 具有良好的用户体验以及应用程序,windows 2008大幅提升了web服务以及应用程序的性能, 让企业在提供和维护资源服务的时候更加得 ...