4. react路由
Posted 友人A ㅤ
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了4. react路由相关的知识,希望对你有一定的参考价值。
1. 相关概念
1.1 SPA
整个应用只有一个完整的页面,称为单页Web应用。
点击页面链接时不会刷新页面,只会做页面的局部刷新。
数据通过ajax请求获取,在前端异步展现。
1.2 路由
一个路由就是一个映射关系(key: value),key为路径,value为function或component。
路由分类
-
后端路由
- value 是 function,用来处理客户端提交的请求
- 注册路由:
router.get(path, function(req, res)
- 工作过程:当node接收到一个请求时,根据请求路径找到匹配的路由,调用路由中的函数来处理请求。返回响应数据
-
前端路由
- 浏览器端路由,value 是 component,用于展示页面内容
- 注册路由:
<Route path="/test" component=Test>
- 工作过程:当浏览器的 path 为 /test 时,当前的路由组件就会变为 Test 组件
1.3 react-router-dom
- react的一个插件库
- 专门用来实现一个 SPA 应用
2. react-router-dom 相关API
前端路由的原理主要是靠BOM的history。
https://react-router.docschina.org/web/guides/philosophy
2.1 基本使用
安装库:npm i react-router-dom
- 引入标签
import Link, BrowserRouter, Route from 'react-router-dom'
- 使用路由链接切换组件,需要将Link标签放在BrowserRouter或HashRouter路由器中
<div>
/* 使用路由链接切换组件 */
<BrowserRouter>
<Link className="list-group-item" to="/about">About</Link>
<Link className="list-group-item" to="/home">Home</Link>
</BrowserRouter>
</div>
- 注册路由,实现根据路由链接展示不同组件
<div>
/* 注册路由--编写路由链接 */
<BrowserRouter>
<Route path="/about" component=About />
<Route path="/home" component=Home />
</BrowserRouter>
</div>
问题:此时点击切换组件时,只有链接变化,组件不会变化。
原因:两者分别用BrowserRouter包裹,意味着它们位于两个路由器当中,是相互独立的。
解决:使用一个路由器包裹全部内容
- 在React中,所有的组件都是
<App />
的组件,所以可以直接在index.js
文件中用路由器将<App />
包裹起来。
// 引入路由器
import BrowserRouter from 'react-router-dom'
// 渲染 App 到页面
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById('root')
);
BrowserRouter 和 HashRouter的区别:
- 底层原理不一样
- BrowserRouter使用的是H5的history API,不兼容IE9及以下版本
- HashRouter使用的是URL的哈希值
- path表现形式不一样
- BrowserRouter的路径中没有#,例如:localhost:3000/demo/test
- HashRouter的路径包含#,例如:localhost:3000/#/demo/test,#后面的内容不作为资源发送给服务器
- 刷新后对路由state参数的影响
- BrowserRouter没有任何影响,因为state保存在history对象中
- HashRouter刷新后会导致路由state参数的丢失
HashRouter可以用于解决一些路径错误相关的问题。
2.2 路由组件和一般组件
一般组件:
- 放在 components 文件夹中
- 书写方式为
<Home />
- 写组件标签时传递了什么,就能接收到对应的props
路由组件:
- 放在 pages 文件夹中
- 书写方式为
<Route path="/home" component=Home />
- 路由组件会收到路由器传递的三个固定属性:history、location、match
2.3 NavLink
选中标签时为其添加高亮效果。
设计原理:动态添加样式类名active。
1. 使用NavLink
使用Link:
使用NavLink:
可以在NavLink中传递属性activeClassName来实现点击时加哪一个样式的类名。
/* 相当于不写activeClassName,因为原本加的类名就是active */
<NavLink activeClassName='active' className="list-group-item" to="/about">About</NavLink>
<NavLink activeClassName='addactive' className="list-group-item" to="/about">About</NavLink>
<NavLink activeClassName='addactive' className="list-group-item" to="/home">Home</NavLink>
.addactive
background-color: bisque !important;
2. 封装NavLink
二次封装后可以减少代码内的重复内容。
- 新建一个一般组件MyNavLink
- 实现MyNavLink
import React, Component from 'react';
import NavLink from 'react-router-dom'
export default class MyNavLink extends Component
render()
// 获取传递过来的props值
const to, title = this.props
return (
<NavLink activeClassName='addactive' className="list-group-item" to=to>title</NavLink>
);
- 使用MyNavLink
<div className="list-group">
/* 使用路由链接切换组件 */
/* <NavLink activeClassName='addactive' className="list-group-item" to="/about">About</NavLink>
<NavLink activeClassName='addactive' className="list-group-item" to="/home">Home</NavLink> */
<MyNavLink to="/about" title="About" />
<MyNavLink to="/home" title="Home" />
</div>
- 如果想在代码中传递多个标签属性,并且将标题做为标签体内容,可以优化代码如下:
标签体内容其实也包含在props中,是标签的一个特殊属性:
<MyNavLink to="/about">About</MyNavLink>
<MyNavLink to="/home">Home</MyNavLink>
import React, Component from 'react';
import NavLink from 'react-router-dom'
export default class MyNavLink extends Component
render()
// 获取传递过来的props值
return (
<NavLink activeClassName='addactive' className="list-group-item" ...this.props />
);
2.4 Switch
当页面中注册的路由非常多时,如果已经匹配到了目标路径,就应该停止往下查找,避免产生过多的消耗性能。
<Route path="/about" component=About />
<Route path="/home" component=Home />
<Route path="/home" component=Test />
此时可以使用Switch标签将所有的路由包裹起来,实现单一匹配,从而提高效率。
<Switch>
<Route path="/about" component=About />
<Route path="/home" component=Home />
<Route path="/home" component=Test />
</Switch>
2.5 路由的模糊匹配与严格匹配
- 模糊匹配:在V5版本中,如果最开始能匹配上,那就能得到结果;而V6版本的模糊匹配需要写成
/home/*
2. 严格匹配:使用exact属性可以开启精准匹配
注意:
严格匹配不要随意开启,否则有时会导致无法继续匹配二级路由
2.6 Redirect
重定向放在路由注册最下方,如果前面的路由都没有匹配上,则由重定向决定路由指向。
<Switch>
<Route path="/about" component=About />
<Route path="/home" component=Home />
<Redirect to="/about" />
</Switch>
2.7 嵌套路由
在注册子路由时要写上父路由的path值,路由的匹配是按照注册路由的顺序进行的。
在Home组件中添加子组件:
<div>
<h2>我是Home的内容</h2>
<div>
<ul className="nav nav-tabs">
<li>
<MyNavLink to="/home/news">News</MyNavLink>
</li>
<li>
<MyNavLink to="/home/message">Message</MyNavLink>
</li>
</ul>
/* 注册路由 */
<Switch>
<Route path="/home/news" component=News />
<Route path="/home/message" component=Message />
</Switch>
</div>
</div>
/* 注册路由--编写路由链接 */
<Switch>
<Route path="/about" component=About />
<Route path="/home" component=Home />
<Redirect to="/home/news" />
</Switch>
2.8 路由组件传参
1. 向路由组件传递params参数
父组件向路由组件传递params参数:
新建Detail子组件,并在组件中接收params参数:
import React, Component from 'react';
const detailData = [
id: '01', content: 'aaa' ,
id: '02', content: 'bbb' ,
id: '03', content: 'ccc'
]
export default class Detail extends Component
render()
const id, title = this.props.match.params
const findResult = detailData.find((detailObj) =>
return detailObj.id == id
)
return (
<ul>
<li>ID:id</li>
<li>TITLE:title</li>
<li>CONTENT:findResult.content</li>
</ul>
);
向路由组件传递params参数后,子组件中能通过this.props获取到传递的值
2. 向路由组件传递search参数
向路由组件传递search参数
在子组件中获取到的search参数为以下效果,需要对其进行处理才能使用
引入qs库,能将urlencoded(即key=value&key=value格式)转为对象形式
import React, Component from 'react';
import qs from 'qs'
const detailData = [
id: '01', content: 'aaa' ,
id: '02', content: 'bbb' ,
id: '03', content: 'ccc'
]
export default class Detail extends Component
render()
// 接收search参数
const search = this.props.location
const id, title = qs.parse(search.slice(1))
const findResult = detailData.find((detailObj) =>
return detailObj.id == id
)
return (
<ul>
<li>ID:id</li>
<li>TITLE:title</li>
<li>CONTENT:findResult.content</li>
</ul>
);
3. 向路由组件传递state参数
向路由组件传递state参数
子组件中接收值:
import React, Component from 'react';
const detailData = [
id: '01', content: 'aaa' ,
id: '02', content: 'bbb' ,
id: '03', content: 'ccc'
]
export default class Detail extends Component
render()
// 接收state参数
const id, title = this.props.location.state ||
const findResult = detailData.find((detailObj) =>
return detailObj.id == id
) ||
return (
<ul>
<li>ID:id</li>
<li>TITLE:title</li>
<li>CONTENT:findResult.content</li>
</ul>
);
当页面刷新的时候也可以保留参数
2.9 push和replace
- push跳转:形成history,可返回上一级
- replace跳转:不会形成history,不可返回到上一级。适用于登录后,不需要重新回到登录页面。
用法:直接在路由标签中写replace属性
2.10 编程式路由导航
可以借助路由身上的history对象上的API来实现路由跳转:
- this.props.history.push()
- this.props.history.replace()
- this.props.history.goBack()
- this.props.history.goForward()
- this.props.history.go()
例子:
export default class Message extends Component
state =
messageArr: [
id: '01', title: '消息1' ,
id: '02', title: '消息2' ,
id: '03', title: '消息3' ,
]
replaceShow = (id, title) =>
// replace跳转 + 携带params参数
// this.props.history.replace(`/home/message/detail/$id/$title`)
// replace跳转 + 携带search参数
// this.props.history.replace(`/home/message/detail?id=$id&title=$title`)
// replace跳转 + 携带state参数
this.props.history.replace(`/home/message/detail`, id, title )
pushShow = (id, title) =>
// push跳转 + 携带params参数
// this.props.history.push(`/home/message/detail/$id/$title`)
// push跳转 + 携带search参数
// this.props.history.push(`/home/message/detail?id=$id&title=$title`)
// push跳转 + 携带state参数
this.props.history.push(`/home/message/detail`, id, title )
render()
const messageArr = this.state;
return (
<div>
<ul>
messageArr.map((msgObj) =>
return (
<li key=msgObj.id>
/* 向路由组件传递params参数 */
/* <Link to=`/home/message/detail/$msgObj.id/$msgObj.title`>msgObj.title</Link> */
/* 向路由组件传递search参数 */
/* <Link to=`/home/message/detail/?id=$msg以上是关于4. react路由的主要内容,如果未能解决你的问题,请参考以下文章