react路由解决方案


react-router:是react router的核心库

react-router-dom:是网页路由的解决方案,依赖于react-router

react-router-native:是react-native解决移动端路由的解决方案,依赖于react-router

下面讲述的是react-router-dom的使用

这里用的react-router版本是5.x

react-router5.x版本和react-router3.x使用上有很大不同

1安装路由模块

npm i –S react-router-dom

2路由的定义

App.jsx

image

这里定义了4个页面

<Router>定义一个路由实例,相当于一个路由容器

<Switch>标签让路由只能匹配单个<Route>,不具包含性的匹配多个路由

5.x的路由具有包含性和3.x的路由完全不同

exact属性让route进行严格匹配,只有路径完全一致才会匹配成功,默认值true,可以省略不写

eq:

image

      在网页中匹配根路径’/’,路由匹配会按从上到下的顺序进行匹配,如果没有<Swith>标签,就会成功匹配’/’,’/about’,’/inbox’,’/coder’所有的<Route>标签,从而展示其相关的组件。

添加<Swith>标签后,路由只能匹配单个<Route>标签,因此这里只会匹配到path=’/’的<Route>标签

但如果在网页中匹配’/about’,这时还是会匹配到path=’/’的路由,因此需要给path=’/’的<Route>标签添加exact属性让其进行严格匹配,只有路径完全等于’/’时才会成功匹配,添加exact属性后路由就不会匹配到path=’/‘的路由上,而是匹配到path=’about’的路由

3.将路由渲染到页面

index.js

image

下面叙述相关的详细的组件

目录结构:

image

Dashboard.jsx  网页根组件

image

这里有个公共组件Header

Header.jsx

image

<Link>标签用来进行路由跳转,默认会被渲染成a标签

About.jsx

image

Inbox.jsx

image

这里面嵌套了两个子路由,对应的组件分别是MessageLinkComponent和Message

其中一个是动态路由,以id值作为动态路径

获取父级路由的路径path:this.props.match.path,这里获取到的path是 ‘/inbox’

与this.props.match.url比较:

this.props.match.path获取的是纯路径,即定义好的路径  ‘/index/:id’

this.props.match.url获取的是资源的路径地址  ‘/index/123’

子路由组件:MessageLinkComponent.jsx

image

实现子路由的跳转,并把id值当成动态路径传出

子路由组件:Message.jsx

image

子路由跳转的内容显示

id值的获取:this.props.match.params.id

Coder.jsx

image

定义了一个子路由,其对应的组件是CoderContent

并且定义了子路由跳转的Link,实现子路由跳转,将相关数据以键值对存放于路径中并传递出去

CoderContent.jsx

image

通过get传值传递来的键值对用node的url模块进行解析,解析出一个以json对象保存的query对象,并将其展示在页面上

url.parse(this.props.location.search,true).query

路由模块的抽离

将路由的定义抽离成一个配置文件routesConfig.js

routesConfig.js

image

相关页面也需要改写

App.jsx

image

这里用三元表达式代替了if-else语句的嵌套

注意:子路由的嵌套要将component属性改写成一个render函数,这样才能将children子路由对象传递给props参数

image

render函数是一个带props参数的箭头函数,结果返回一个react组件实例对象(jsx对象)

并把children子路由挂载在实例对象的children属性上,相当于覆盖了props.children属性。

 

从这里可以看出<Route>标签的作用仅仅只是充当了一个中间组件,最后还是需要通过render

函数来渲染相关的即将展示的组件,并通过props参数把挂在<Route>标签上的属性传给组件实例

例如:<Route>上的path属性最终会以this.props.match.path的形式在react组件实例中获取到

 

Inbox.jsx

image

Coder.jsx

image

image

js实现路由跳转

网上有很多种方法实现,这里使用比较简单的两种方法

1.官方推荐的组件内路由跳转

官方推荐使用高级路由组件withRouter来包裹需要用到跳转的组件。

这里对组件Header.jsx进行修改

image

被withRouter包裹的Header会给props注册一个history对象,这个history对象正是整个路由默认使用的history对象(创建BrowserRouter组件后会有一个默认的history,但不会直接暴露出来给你使用)

history对象内容:

image

可以通过event.target获取dom对象,进而通过js操作dom获取元素属性to的值,即获取跳转路径,并通过this.props.push()来进行跳转

eq: this.props.history.push(e.target.getAttribute('to'))

也可以通过event.target.dataset.to来获取路径值,不过进行跳转的标签上要有定义data-to属性来保存路径

eq: this.props.history.push(e.target.dataset.to)

2.自己创建一个history对象实例来控制跳转 (比较自由)

创建history模块

image

history.js

image

这里用了react的history库来创建,并将实例导出。

注意将history对象引入到Router组件中,让整个路由实例使用我们创建出来的history对象,否则无法生效

App.jsx

image

image

导入后发出警告:

image

原来BrowserRouter忽略了history属性,因此通过BrowserRouter创建的路由也都不用手动导入history。

为了能使用自定义的history,只好不使用提供好的BrowserRouter组件来创建路由,而是用最原始的Router组件来创建路由实例。

image===》

image

然后只需要在想要使用跳转的组件中导入我们创建好的history实例,并操作history对象就能实现跳转了

eq:

import history from ‘modules/history’

history.push(e.target.getAttribute('to'))

以Header.jsx为例:

image

实际上这里的this.props.history和导入的history已经是同一个对象了

实验:

console.log(history==this.props.history) //true

推导可以知道withRouter组件给Header注册的this.props.history属性,来自于App.jsx中导入的history => <Router history={history}> ,并且通过withRouter传递给其他组件

补充

由于Route组件进行的条件判断太过繁杂,于是将Switch组件和Route组件组合封装成一个Routes组件,避免页面数量多时,总要重复写这段判断代码

Routes.js

image

由于对Route组件外部包裹了Routes这样一个组件,导致某些组件在调用Routes时,没有把上一层的Route组件的属性传递下去,Route组件其实就是个中间组件并且包裹了个普通组件,并把Route上的属性传递给普通组件。

正常:Route.props –> Component.props

嵌套后: Route.props –> Component.props –>Route2.props –> Component2.props

Component.props –>Route2.props 这个阶段会用到 Component.props的部分值

包裹Routes后:Routes.props –> Route.props  –> Component.props 

因此进行路由嵌套后是这个样:

Routes.props –> Route.props  –> Component.props  -> Routes2.props –> Route2.props  –> Component2.props

这里得解决:Component.props  -> Routes2.props 这个阶段的传值,Routes2作用其实就是承接Component中的props,目的是为了能让Route2能正常工作

于是得进行手动传值:<Routes {...this.props}></Routes>

并且在Routes组件中增加了判断,判断接下来进行渲染的config用的是routesConfig还是由组件传递下来的children

this.props.children?(this.config=this.props.children):(this.config=routesConfig)

修改后的App.jsx变得极为简单:

image

Inbox.jsx也一样

image

同理作用于Coder.jsx


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM