React路由
# React路由
# 简介
# SPA理解
- 单页 Web 应用 (single page web application, SPA)。
- 整个应用只有一个完整的页面。
- 点击页面中的链接不会刷新页面,只会做页面的局部更新。
- 数据都需要通过 ajax 请求获取,并在前端异步展现。
- 单页面,多组件。
# 路由理解
什么是路由?
- 一个路由就是一个映射关系
key:value
key
为路径,value
可能是function
或component
路由分类?
- 后端路由
- 理解:
value
是function
,用来处理客户端提交的请求 - 注册路由:
router.get(path, function(requires))
- 工作过程:当 node 接收到一个请求时,根据请求路由找到匹配的路由,调用路由中的函数来处理请求,返回响应数据。
- 理解:
- 前端路由
- 浏览器路由,
value
时component
,用于展示页面内容 - 注册路由:
<Route path="/test" component={Test}>
- 工作过程:当浏览器的 path 变为
/test
时,当前路由组件就会变为 Test 组件
- 浏览器路由,
# react-router-dom理解
- react的一个插件库
- 专门用来实现一个SPA应用
- 基于react的项目基本都会用到此库
# react-router-dom相关API
# 安装
# 版本5
npm install react-router-dom@5
# 版本6
npm install react-router-dom@6
1
2
3
4
2
3
4
# 基本使用
- 明确界面中的导航区、展示区
- 导航区的 a 标签改为 Link 标签,
<Link to="/home">Home</Link>
- 展示区写 Route 标签进行路径的匹配,
<Route path="/home" component={Home}/>
- 可以在
<App>
的最外侧包裹一个<BrowserRouter>
或者<HashRouter>
# 内置组件
# Link和Router
//创建外壳组件APP
import React,{Component} from 'react'
import {Link, BrowserRouter, Route} from 'react-router-dom'
import Home from './components/Home/Home'
import About from './components/About/About'
export default class App extends Component{
render(){
//通过 ...将状态中的全部赋值过去
return (
<div>
<BrowserRouter>
<Link to="/about">About</Link>
/or/
<Link to="/home">Home</Link>
<br></br>
<Route path="/about" component={About}/>
<Route path="/home" component={Home}/>
</BrowserRouter>
</div>
)
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<Link>
和<Router>
都要放在<BrowserRouter>
标签内。
# NavLink
点击后默认添加 actvie 属性
可以使用<NavLink activeClassName="xxx">
自定义选中时 active 的命名
封装NavLink,不用重复写一些相同的设置,
import React, { Component } from 'react'
import { NavLink } from 'react-router-dom'
export default class MyNavLink extends Component {
render() {
return (
// 标签题内容是一个特殊的标签属性,通过this.props.children可以获取标签体内容
<NavLink activiteClassName="xxx" className="list-group-item" {...this.props}/>
)
}
}
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
使用:
<MyNavLink to="/home" a={1} b={2} c={3}>Home</MyNavLink>
1
多级路径样式丢失问题:使用%PUBLIC_URL%
# Switch
<Switch>
<Route path="/about" component={About}/>
<Route path="/home" component={Home}/>
<Route path="/home" component={Test}/>
</Switch>
1
2
3
4
5
6
2
3
4
5
6
通常情况下,path和component是一一对应关系。使用Switch提高路由匹配效率,匹配第一个路径后就不往下匹配了。
# 模糊匹配
默认使用模糊匹配,输入的路径必须包含匹配路径,且顺序要一致(/a/home/b
与/home
顺序不匹配)。
<MyNavLink to="/home/a/b">Home</MyNavLink>
<Switch>
<Route path="/about" component={About}/>
<Route path="/home" component={Home}/>
</Switch>
1
2
3
4
5
6
2
3
4
5
6
开启严格模式:exact={true}
<MyNavLink to="/home/a/b">Home</MyNavLink>
<Switch>
<Route exact={true} path="/about" component={About}/>
<Route exact={true} path="/home" component={Home}/>
</Switch>
1
2
3
4
5
6
2
3
4
5
6
严格匹配不要随便开启,需要再开启,有些时候开启会导致无法继续匹配二级路由。
# Redirect
一般写在所有路由注册的最下方,当所有路由都无法匹配时,跳转到Redirect指定的路由
<Switch>
<Route path="/about" component={About}/>
<Route path="/home" component={Home}/>
<Redirect to="/home"/>
</Switch>
1
2
3
4
5
2
3
4
5
# 路由组件与一般组件
- 写法不同:
- 一般组件:
<Demo/>
- 路由组件:
<Route path="/demo" component={Demo}/>
- 一般组件:
- 存放位置不同:
- 一般组件:components
- 路由组件:pages
- 接收到的props不通过:
- 一般组件:写组件标签时传递
- 路由组件:接收到三个固定属性
- history
- go(n):根据传入参数1、2、-2回退或前进
- goBack():回退
- goForward():前进
- push(path, state):留下历史记录的跳转
- replace(path, state):不留历史记录的跳转
- location
- pathname
- search
- state
- match
- params
- path
- url
- history
# 嵌套路由使用
1级路由
<MyNavLink to="/home">Home</MyNavLink>
<MyNavLink to="/about">About</MyNavLink>
<Switch>
<Route path="/home" component={Home}/>
<Route path="/about" component={About}/>
</Switch>
1
2
3
4
5
6
2
3
4
5
6
2级路由:
<MyNavLink to="/home/news">News</MyNavLink>
<MyNavLink to="/home/message">Message</MyNavLink>
<Switch>
<Route path="/home/news" component={Home} />
<Route path="/home/message" component={Message} />
</Switch>
1
2
3
4
5
6
2
3
4
5
6
# 向路由传递参数
# 传递params参数
传递
<Link to=`/home/message/${msg.id}/${msg.title}`>{msg.title}</Link>
<Route path="/home/message/:id/:title" component={Detail} />
1
2
3
2
3
接收
const {id,title} = this.props.match.params
1
# 传递search参数
传递
<Link to=`/home/message/?id=${msg.id}&title=${msg.title}`>{msg.title}</Link>
<Route path="/home/message" component={Detail} />
1
2
3
2
3
接收
import qs from "querystring"
// urlencoded key=value&key=value
// qs.stringify(obj) obj => urlencoded
// qs.parse(str) urlencoded => obj
const {search} = this.props.location.search
const {id,title} = qs.parse(search.slice(1))
1
2
3
4
5
6
7
2
3
4
5
6
7
# 传递state参数
与组件的state不同;与其他两种方法相比,参数不会显示在地址栏上
传递
<Link to={{pathname:'/home/message', state:{id:msg.id,title:msg.title}}}>{msg.title}</Link>
<Route path="/home/message" component={Detail} />
1
2
3
2
3
接收
const {id, title} = this.props.location.state || {} // 防止浏览器清除缓存后找不到对象时报错
1
# push与replace
push:默认模式
每一次跳转路由都是一个压栈操作,点击浏览器的后腿就可以返回上一个页面
replace:<Link replace={true} to="/about">About</Link>
同级别的消息会替换,不会留下历史记录。
# 编程式路由导航
借助this.prop.history
对象上的API对路由进行跳转、前进、后退的操作。
- this.prop.history.push()
- this.prop.history.replace()
- this.prop.history.goBack()
- this.prop.history.goForward()
- this.prop.history.go())
replaceShow = (id,title) {
// replace跳转 + 携带params参数
this.props.history.replace(`/home/message/detail/${id}/${title}`)
// replace跳转 + 携带query参数
this.props.history.replace(`/home/message/detail?id=${id}&title=${title}`)
// replace跳转 + 携带state参数
this.props.history.replace(`/home/message/detail`, {id:id,title:title})
}
pushShow = (id,title) {
// push跳转 + 携带params参数
this.props.history.push(`/home/message/detail/${id}/${title}`)
// push跳转 + 携带query参数
this.props.history.push(`/home/message/detail?id=${id}&title=${title}`)
// replace跳转 + 携带state参数
this.props.history.push(`/home/message/detail`, {id,title})
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<button onClick={() => this.replaceShow(id, title)}查看</button>
1
# withRouter
一般组件没有history,使用withRouter
可以加工一般组件,让一般组件具备路由组件具有的API
import React, { Component } from 'react'
import { withRouter } from 'react-router-dom'
class Home extends Component {
back = () => {
this.props.history.goBack();
}
render() {
return (
<div>
Home内容
<button onClick={this.back}>back</button>
</div>
)
}
}
export default withRouter(Home)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# BrowersRouter与HashRouter
底层原理
- BrowserRouter使用的是H5的history API,不兼容IE9及以下版本
- HashRouter使用的是URL的哈希值
url表现形式
- BrowserRouter的路径没有
#
,例如localhost:3000/demo/test
- HashRouter的路径包含
#
,例如localhost:3000/#/demo/test
刷新后对路由state参数的影响
- BrowserRouter没有任何影响,因为state保存在history对象中
- HashRouter刷新后会导致路由state参数的丢失
备注
- HashRouter可以用于解决一些路径错误相关的问题
编辑 (opens new window)
上次更新: 2023/09/06, 19:01:56