5 react-router
5.1 相关理解
- SPA的理解:
- 单页Web应用(single page web application, SPA)
- 整个页面只有一个完整的页面
- 点击页面中的连接不会刷新页面,只做页面的局部更新
- 数据都需要通过ajax请求获取,在前端异步展现
- 路由的理解
- 什么是路由
- 一个路由就是一个映射关系{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组件
- 后端路由
- 什么是路由
- react-router 的理解
- react 的一个插件库
- 专门用来实现一个SPA应用
- 基于react的项目基本都会用到此库
5.2 react-router-dom 相关API
-- 安装
yarn add react-router-dom
npm install --save react-router-dom
5.3 基本路由使用
-
路由组件与一般组件
-
写法不同:
- 一般组件:
<Demo />
- 路由组件:
<Route path="/demo" component={Demo} />
- 一般组件:
-
存放位置不同:
- 一般组件: components
- 路由组件:pages
-
接收到的props不同:
-
一般组件:写组件标签时传递了什么,就能收到了什么
-
路由组件:接收到三个固定属性
history: go: ƒ go(n) goBack: ƒ goBack() goForward: ƒ goForward() push: ƒ push(path, state) replace: ƒ replace(path, state) location: pathname: "/about" search: "" state: undefined match: params: { } path: "/about" url: "/about"
-
-
-
NavLink
的使用- 点击哪了,那个加active 类
activeClassName="atguigu"
-
自封装
MyNavLink
<MyNavLink to="/about" a={ 1} b={ 2}>About</MyNavLink> <MyNavLink to="/home">Home</MyNavLink>
export default class MyNavLink extends Component { render() { console.log(this.props); // const {title} = this.props return ( // <NavLink className="list-group-item" {...this.props}>{this.props.children}</NavLink> <NavLink className="list-group-item" { ...this.props}></NavLink> ) } }
-
解决资源丢失(3种)
-
HashRouter #后边的东西认为是前端东西,不走缓存
-
./css/bootstrap.css ---> /css/bootstrap.css ---> %PUBLIC_URL%/css/....
-
-
路由的模糊与严格匹配
-
模糊匹配
<MyNavLink to="/home/a/b">Home</MyNavLink> // it could <MyNavLink to="/c/home/a/b">Home</MyNavLink> // wrong
-
精准匹配
{ /* 注册路由,展示内容 严格匹配 */} <Route path="/about" component={ About} /> <Route exact={ true} path="/home" component={ Home} />
-
-
Redirect的使用
重定向
一般写在所有路由注册的最下方,当所有路由都无法匹配时,跳转到Redirect指定的路由
<Switch> { /* 注册路由,展示内容 */} <Route path="/about" component={ About} /> <Route path="/home" component={ Home} /> <Redirect to="/about"></Redirect> </Switch>
5.4 嵌套路由使用
- 注册子路由时要写上父路由的path值
- 路由的匹配是按照注册路由的顺序进行的
<div>
<h3>我是Home的内容</h3>
<ul class="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>
<Route path="/home/message" component={
Message}></Route>
<Redirect to="/home/news"></Redirect>
</Switch>
</div>
5.5 向路由组件传递参数数据
-
向路由组件传递
params
参数路由链接:携带参数
注册路由:声明接受
接收参数:this.porps.match.params
messageArr.map((msgObj) => { return ( <li key={ msgObj.id}> { /* 向路由组件传递params参数 */} <Link to={ `/home/message/detail/${ msgObj.id}/${ msgObj.title}`}>{ msgObj.title}</Link> </li> ) }) { /* 注册路由 */} <Route path="/home/message/detail/:id/:title" component={ Detail} /> // 接收 const { id, title} = this.props.match.params;
-
向路由组件传递
search
参数路由链接:携带参数
注册路由:无需声明,正常注册即可
接收参数:this.props.location.search
querystring
库 : urlencoded 编码与 Json 转化import qs from 'querystring' let obj = { name:'tom', age:18} qs.stringfy(obj) // name=tom&age=18 let str = 'name=tom&age=18' qs.parse(str) // {name:'tom', age:18}
messageArr.map((msgObj) => { return ( <li key={ msgObj.id}> { /* 向路由组件传递params参数 */} <Link to={ `/home/message/detail/?id=${ msgObj.id}&title=${ msgObj.title}`}>{ msgObj.title}</Link> </li> ) }) { /* 注册路由 search 参数无需生命接受,正常注册路由即可 */} <Route path="/home/message/detail" component={ Detail} /> // 接收search参数 const { search} = this.props.location const { id, title} = qs.parse(search.slice(1))
-
向路由组件传递
state
参数路由链接:携带参数
注册路由:无需声明
接收参数:
this.props.location.state
ps:刷新也可以保留住参数
messageArr.map((msgObj) => { return ( <li key={ msgObj.id}> { /* 向路由组件传递params参数 */} <Link to={ { pathname:'/home/message/detail', state:{ id:msgObj.id, title : msgObj.title } }} >{ msgObj.title}</Link> </li> ) }) <Route path="/home/message/detail" component={ Detail} /> // 接收state参数 const { id, title} = this.props.location.state || { } const findResult = data.find((detailObj)=>{ return detailObj.id === id; }) || { }
5.6 多种路由跳转方式
- push
- replace
5.7 编程式路由导航
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}`)
// push跳转+携带state参数
this.props.history.replace(`/home/message/detail`, {
id:id, title:title})
}
pushShow = (id, title)=>{
// push跳转+携带params参数
this.props.hsistory.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:id, title:title})
}
5.8 withRouter使用
import React, {
Component } from 'react'
import {
withRouter} from 'react-router-dom'
class Header extends Component {
/*
只有路由组件才有history
一般组件没有history
withRouter 可以让一般组件用于路由组件的history
*/
back = () => {
this.props.history.goBack();
}
forward = () => {
this.props.history.goForward();
}
go = () => {
this.props.history.go(-2);
}
render() {
// console.log('header组件收到的props是', this.props);
return (
<div>
<h2>React Router Demo</h2>
<button onClick={
this.back}>回退</button>
<button onClick={
this.forward}>前进</button>
<button onClick={
this.go}>go</button>
</div>
)
}
}
/*
暴露withRouter的返回值
给一般组件加工 history 等api
withRouter的返回值是要给新组件
*/
export default withRouter(Header);
5.9 BrowserRouter与HashRouter
- 底层原理不同:
- BrowserRouter使用的是H5的history API, 不兼容IE9及以下版本。
- HashRouter使用的是URL的哈希值
- url表现形式不一样:
- BrowserRouter的路径种没有#,例如:
localhost:3000/demo/test
- HashRouter的路径包含#,例如:
localhost:3000/#/demo/test
- BrowserRouter的路径种没有#,例如:
- 刷新后对路由state参数的影响:
- BrowserRouter没有任何影响,因为state保存在history对象中
- HashRouter刷新后会导致路由state参数的丢失
- PS:HashRouter可以用于解决一些路径错误相关的问题。