以 hash 形式(也可使用 History API 来处理)为例,当 url 的 hash 发生变化时,触发 hashchange 注册的回调,回调中去进行不一样的操做,进行不一样的内容的展现html
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();
能够从 react-router/ Link 中看到,对该组件的点击事件进行了阻止了浏览器的默认跳转行为,而改用 history 模块的 pushState 方法去触发 url 更新。html5
给history注册了lisetner事件,也就是里面的setState函数;node
history.push(pathname,state)函数执行,这里会执行注册的listener函数react
listerer中的React的setState会执行;redux
React组件更新;api
其实不管是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) }) }) }
一、react-router依赖基础 - historyreact-router
history是一个独立的第三方js库,能够用来兼容在不一样浏览器、不一样环境下对历史记录的管理,拥有统一的API。具体来讲里面的history分为三类:架构
node环境下: 主要存储在memeory里面,对应createMemoryHistory
createMemoryHistory: 在内存中进行历史记录的存储
执行URL前进
检测URL回退
二、react-router的基本原理
框架去拦截浏览器跳转,本身去同步UI组件
其中在react-router中,URL对应Location对象,而UI是由react components来决定的,这样就转变成location与components之间的同步问题
经过router声明了一份含有 path to component 的各个映射的路由表。
react-router 还提供的 Link 组件(以下),做为提供更新 url 的途径,触发 Link 后最终将经过如上面定义的路由表进行匹配,并拿到对应的 component 及 state 进行 render 渲染页面。
三、从点击 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); }); }); }
可看到,上面代码中,主要分为两部分
url 更新主要有两种方式:简单的 hash 更新或使用 history api 进行地址更新。在 react-router 中,其提供了 Link 组件,该组件能在 render 中使用,最终会表现为 a 标签,并将 Link 中的各个参数组合放它的 href 属性中。能够从 react-router/ Link 中看到,对该组件的点击事件进行了阻止了浏览器的默认跳转行为,而改用 history 模块的 pushState 方法去触发 url 更新
至于前进与后退的实现,是经过监听 popstate 以及 hashchange 的事件,当前进或后退 url 更新时,触发这两个事件的回调函数,回调的执行方式 Link 大体相同,最终一样更新了 UI ,这里就再也不说明。
react-router 主要是利用底层 history 模块的机制,经过结合 react 的架构机制作一层包装.
const about = (location, cb) => { require.ensure([], require => { cb(null, require('../Component/about').default) },'about') } //配置route <Route path="helpCenter" getComponent={about} />