阅读源码是提升编程功底和深层次理解原理的不二方法,强烈建议大家初次学习源码就拿前端路由开始。因为路由组件可以说和我们开发项目息息相关了,而且其源码结构也非常清晰,可以说是初识源码的绝佳例子。
react路由库的关系
react-router-dom,react-router和history库三者有什么关系?
history可以理解为react-router的核心,也是整个路由原理的核心,里面集成了popState(),history.pushState()等底层路由实现的原理方法。
react-router可以理解为是react-router-dom的核心,里面封装了Router、Route、Switch等核心组件,实现了从路由的改变到组件的更新的核心功能,在我们的项目中只要一次性引入react-router-dom就可以了
react-router-dom在react-router的核心基础上,添加了用于跳转的Link组件,history模式的BrowserRouter以及hash模式下的HashRouter组件等。所谓BrowserRouter和HashRouter,也只不过是用了history库中的createBrowserHistory和createHashHistory方法。
实现原理
单页面应用路由实现原理是:切换url → 监听url变化 → 渲染不同的页面组件。主要的方式有history模式和hash模式。
history模式
1.改变路由
(1). history.pushState(state,title,path),state → 一个与指定网址相关的状态对象,popstate事件触发时,该对象会传入回调函数。如果不需要可填null;
title:新页面的标题,但是所有浏览器目前都忽略这个值,可填null。 path:新的网址,必须与当前页面处在同一个域。浏览器的地址栏将显示这个地址。
(2). history.replaceState(state,title,path)参数和pushState一样,这个方法会修改当前的history对象记录,history.length的长度不会改变。
2.监听路由
popstate事件:window.addEventListener('popstate',function(e)){xxx}。
同一个文档的history对象出现变化时,就会触发popstate事件。而history.pushState可以使浏览器地址改变,但是无需刷新页面。
注意点:用history.pushState()或者history.replaceState()不会触发popstate事件。popstate事件只会在浏览器某些行为下触发,比如点击后退、前进按钮或者调用history.back()、history.forward()、history.go()方法。
hash模式
1.改变路由
window.location.hash:通过window.location.hash属性获取和设置hash值。
2.监听路由
window.addEventListener('hashchange',function(e){xxx})
源码分析
总结
history库提供了核心api,如监听路由,更改路由的方法并保存路由状态state。
react-router提供路由渲染组件,路由唯一性匹配组件,重定向组件等功能组件。
流程分析
当地址栏改变url,组件的更新渲染都经历什么?
拿history举例,当url改变,首先触发history调用事件监听popstate事件,触发回调函数handlePopState,触发history下面的setstate方法,产生新的location对象。
然后通知Router组件更新location并通过context上下文传递,switch通过传递的更新流,匹配出符合的Route组件渲染,最后由Route组件取出context内容,传递给渲染页面,渲染更新。
当我们调用history.push方法,切换路由,组件的更新渲染过程。
当我们调用history.push方法,首先调用history的push方法,通过history.pushState来改变当前url,接下来触发history下面的setState,接下来的步骤就和上面一模一样了。
记录记录!