如何实现一个ReactRouter?针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。

ReactRouter的实现
ReactRouter是React的核心组件,主要是作为React的路由管理器,保持UI与URL同步,其拥有简单的API与强大的功能例如代码缓冲加载、动态路由匹配、以及建立正确的位置过渡处理等。
描述
React Router是建立在history对象之上的,简而言之一个history对象知道如何去监听浏览器地址栏的变化,并解析这个URL转化为location对象,然后router使用它匹配到路由,最后正确地渲染对应的组件,常用的history有三种形式:Browser History、Hash History、Memory History。
Browser History
Browser History是使用React Router的应用推荐的history,其使用浏览器中的History对象的pushState、replaceState等API以及popstate事件等来处理URL,其能够创建一个像https://www.example.com/path这样真实的URL,同样在页面跳转时无须重新加载页面,当然也不会对于服务端进行请求,当然对于history模式仍然是需要后端的配置支持,用以支持非首页的请求以及刷新时后端返回的资源,由于应用是个单页客户端应用,如果后台没有正确的配置,当用户在浏览器直接访问URL时就会返回404,所以需要在服务端增加一个覆盖所有情况的候选资源,如果URL匹配不到任何静态资源时,则应该返回同一个index.html应用依赖页面,例如在Nginx下的配置。
location / {
try_files $uri $uri/ /index.html;
}Hash History
我们来实现一个非常简单的 我们可以看一下 我们以 接下来我们到 我们在使用时都是使用 我们实际上我们可能写的最多的就是 关于如何实现一个ReactRouter问题的解答就分享到这里了,希望以上内容可以对大家有一定的帮助,如果你还有很多疑惑没有解开,可以关注创新互联行业资讯频道了解更多相关知识。Hash符号即#原本的目的是用来指示URL中指示网页中的位置,例如/tupian/20230522/index.html HistoryMemory History不会在地址栏被操作或读取,这就可以解释如何实现服务器渲染的,同时其也非常适合测试和其他的渲染环境例如React Native,和另外两种History的一点不同是我们必须创建它,这种方式便于测试。const history = createMemoryHistory(location);
实现
Browser History模式与Hash History模式的实现,因为H5的pushState方法不能在本地文件协议file://运行,所以运行起来需要搭建一个http://环境,使用webpack、Nginx、Apache等都可以,回到Browser History模式路由,能够实现history路由跳转不刷新页面得益与H5提供的pushState()、replaceState()等方法以及popstate等事件,这些方法都是也可以改变路由路径,但不作页面跳转,当然如果在后端不配置好的情况下路由改编后刷新页面会提示404,对于Hash History模式,我们的实现思路相似,主要在于没有使用pushState等H5的API,以及监听事件不同,通过监听其hashchange事件的变化,然后拿到对应的location.hash更新对应的视图。
分析
ReactRouter的实现,commit id为eef79d5,TAG是4.4.0,在这之前我们需要先了解一下history库,history库,是ReactRouter依赖的一个对window.history加强版的history库,其中主要用到的有match对象表示当前的URL与path的匹配的结果,location对象是history库基于window.location的一个衍生。ReactRouter将路由拆成了几个包:react-router负责通用的路由逻辑,react-router-dom负责浏览器的路由管理,react-router-native负责react-native的路由管理。BrowserRouter组件为例,BrowserRouter在react-router-dom中,它是一个高阶组件,在内部创建一个全局的history对象,可以监听整个路由的变化,并将history作为props传递给react-router的Router组件,Router组件再会将这个history的属性作为context传递给子组件。// packages\react-router-dom\modules\HashRouter.js line 10
class BrowserRouter extends React.Component {
history = createHistory(this.props);
render() {
return Router组件,Router组件创建了一个React Context环境,其借助context向Route传递context,这也解释了为什么Router要在所有Route的外面。在Router的componentWillMount中,添加了history.listen,其能够监听路由的变化并执行回调事件,在这里即会触发setState。当setState时即每次路由变化时-> 触发顶层Router的回调事件->Router进行setState-> 向下传递nextContext此时context中含有新的location-> 下面的Route获取新的nextContext判断是否进行渲染。// line packages\react-router\modules\Router.js line 10
class Router extends React.Component {
static computeRootMatch(pathname) {
return { path: "/", url: "/", params: {}, isExact: pathname === "/" };
}
constructor(props) {
super(props);
this.state = {
location: props.history.location
};
// This is a bit of a hack. We have to start listening for location
// changes here in the constructor in case there are any Router来嵌套Route,所以此时就到Route组件,Route的作用是匹配路由,并传递给要渲染的组件props,Route接受上层的Router传入的context,Router中的history监听着整个页面的路由变化,当页面发生跳转时,history触发监听事件,Router向下传递nextContext,就会更新Route的props和context来判断当前Route的path是否匹配location,如果匹配则渲染,否则不渲染,是否匹配的依据就是computeMatch这个函数,在下文会有分析,这里只需要知道匹配失败则match为null,如果匹配成功则将match的结果作为props的一部分,在render中传递给传进来的要渲染的组件。Route接受三种类型的render props,、、,此时要注意的是如果传入的component是一个内联函数,由于每次的props.component都是新创建的,所以React在diff的时候会认为进来了一个全新的组件,所以会将旧的组件unmount再re-mount。这时候就要使用render,少了一层包裹的component元素,render展开后的元素类型每次都是一样的,就不会发生re-mount了,另外children也不会发生re-mount。// \packages\react-router\modules\Route.js line 17
class Route extends React.Component {
render() {
return (
Link这个标签了,所以我们再来看一下组件,我们可以看到Link最终还是创建一个a标签来包裹住要跳转的元素,在这个a标签的handleClick点击事件中会preventDefault禁止默认的跳转,所以实际上这里的href并没有实际的作用,但仍然可以标示出要跳转到的页面的URL并且有更好的html语义。在handleClick中,对没有被preventDefault、鼠标左键点击的、非_blank跳转的、没有按住其他功能键的单击进行preventDefault,然后push进history中,这也是前面讲过的路由的变化与 页面的跳转是不互相关联的,ReactRouter在Link中通过history库的push调用了HTML5 history的pushState,但是这仅仅会让路由变化,其他什么都没有改变。在Router中的listen,它会监听路由的变化,然后通过context更新props和nextContext让下层的Route去重新匹配,完成需要渲染部分的更新。// packages\react-router-dom\modules\Link.js line 14
class Link extends React.Component {
handleClick(event, history) {
if (this.props.onClick) this.props.onClick(event);
if (
!event.defaultPrevented && // onClick prevented default
event.button === 0 && // ignore everything but left clicks
(!this.props.target || this.props.target === "_self") && // let browser handle "target=_blank" etc.
!isModifiedEvent(event) // ignore clicks with modifier keys
) {
event.preventDefault();
const method = this.props.replace ? history.replace : history.push;
method(this.props.to);
}
}
render() {
const { innerRef, replace, to, ...rest } = this.props; // eslint-disable-line no-unused-vars
return (
网页标题:如何实现一个ReactRouter-创新互联
URL链接:http://www.scyingshan.cn/article/dceepi.html


咨询
建站咨询
