如何实现一个ReactRouter-创新互联
如何实现一个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 History
Memory 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-创新互联
文章源于:http://scyanting.com/article/dceepi.html