路由
一、版本5路由
1. react-router-dom
2. 路由的使用
1. 基础使用
- 安装:
yarn add react-router-dom@5
- 明确好界面中的导航区、展示区
- 导航区
Link
标签包裹
<Link to="/home">Home</Link>
- 展示区写在
Route
标签进行匹配
<Route path='/home' component={Home} />
<App/>
最外侧包裹一个<BrowserRouter>
或者<HashRouter>
2. 路由组件和一般组件
- 写法不同:
- 一般组件:
<Demo/>
- 路由组件:
<Route path='/home' component={Home} />
- 一般组件:
- 存放位置不同:
- 一般组件写在
components
文件夹 - 路由组件一般写在
pages
文件夹中,
- 一般组件写在
- 接收到的
props
不同:- 一般组件:写组件标签时传递了什么,就能收到什么
- 路由组件:接收三个固定的属性(常用)
history: go: ƒ go(n) goBack: ƒ goBack() goForward: ƒ goForward() push: ƒ push(path, state) replace: ƒ replace(path, state) location: pathname: "/home" search: "" state: undefined match: params: {} path: "/home" url: "/home"
3. NavLink
与封装NavLink
NavLink
可以实现路由链接的高亮,通过activeClassName
指定样式名- 标签体内容是一个特殊的标签属性
- 通过
this.props.children
可以获取标签体内容
使用NavLink
封装NavLink
4.Switch
的使用
- 通常情况下,
path
和component
是一一对应的关系 Switch
可以提高路由匹配效率(单一匹配)
5. 解决多级路径刷新页面样式丢失的问题
publick/index.html
中,引入样式时不写./
写/
(常用)publick/index.html
中,引入样式时不写./
写%PUBLIC_URL%
(常用)- 使用
HashRouter
- 原因:加载不存在的路径时,默认把
publick/index.html
返回
6. 路由的模糊匹配和严格匹配exact
- 默认使用的使模糊匹配(简单记:【输入的路径】必须包含要【匹配的路径】,且顺序一致)
- 开启严格匹配,
<Route exact path='/about' component={About}/>
- 严格匹配不要随便开启,需要再开,有些时候开启会导致无法继续匹配二级路由
7. Redirect
的使用
- 一般写在所以路由注册的最下方,当所以路由无法匹配时,跳转到Redirect指定的路由
- 编码
<Switch>
<Route path='/home' component={Home} />
<Route path='/about' component={About} />
{/* 写在最底部,重定向, 路由都匹配不上,就去 to ... */}
<Redirect to='/home'/>
</Switch>
8. 嵌套路由
- 注册子路由时要写上父路由的
path
值 - 路由的匹配是按照注册路由的顺序进行的
9. 向路由组件传递参数
1. params
参数
- 路由链接(携带参数):
<Link to={`/about/message/detail/${item.id}/${item.title}`}>{item.title}</Link>
- 注册路由(声明接收):
<Route path='/about/message/detail/:id/:title' component={Detail}/>
- 接收参数:
const {id, title} = this.props.match.params
2. search
参数
- 路由链接(携带参数):
<Link to={`/about/message/detail?id=${item.id}&title=${item.title}`}>{item.title}</Link>
- search参数无需声明接收,正常注册路由即可:
<Route path='/about/message/detail' component={Detail}/>
- 接收参数:
// search 接收参数 react自动安装的库
import qs from 'querystring'
const {search} = this.props.location
const {id, title} = qs.parse(search.slice(1))
- 备注: 获取到
search
是urlencoded
编码,需要借助querystring
解析
3. state传递参数
- 路由链接(携带参数):
<Link to={{pathname:'/about/message/detail', state:{
id: item.id,
title: item.title
}}}>{item.title}</Link>
- 注册路由(声明接收):
// state参数无需声明接收,正常注册路由即可
<Route path='/about/message/detail' component={Detail}/>
- 接收参数:
const {id, title} = this.props.match.state
- 备注: 刷新也可以保留住参数
9. push
与replace
- 加上
replace
属性,将不会再进行压栈,浏览器不会有回退记录
<MyNavLink replace to='/about/message'>Message</MyNavLink>
10. 编程式导航
借助this.props.history
对象上的API
对操作路由跳转、前进、后退
this.props.history.push()
this.props.history.replace()
this.props.history.goBack()
this.props.history.goForward()
this.props.history.go()
11. withRouter
withRouter
可以加工一般组件,让一般组件具备路由组件所持有的API
withRouter
的返回值是一个新组件
import { withRouter } from 'react-router-dom'
export default withRouter(Hearder)
示例中:普通组件想要实现路由跳转
App.js
中:
12. 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
可以用于解决一些路径错误相关的问题
二、版本6路由
1. 概述
react Router
三个不同的包发布在npm
上:它们分别是:react-router
: 路由的核心库,提供很多的:组件,钩子react-router-dom
: 包含react-router
所以内容,并添加一些专门用于DOM
组件。例如<BrowerRouter>
等react-router-native
: 包含react-router
所以内容,并添加一些专门用于ReactNative
的API
。例如<NativeRouter>
等
- 与
React Router 5.x
版本相比,改变了什么?- 内置组件的变化:移除
<Switch/>
,新增<Routes/>
等 - 语法的变化:
component={About}
变为elemet={<About/>}
等 - 新增多个
hook
:useParams
、useNavigate
、useMatch
等 - 官方明确推荐函数式组件了!!!
…
- 内置组件的变化:移除
2. Component
1. <BerwserRouter>
2. <HashRouter>
3. <Routes/>和<Route/>
v6
版本中移除了<Switch>
,引入了新的替代者:<Routes>
<Routes>
和<Route>
要配合使用,且必须要用<Routes>
包裹<Route>
<Route>
相当于一个if
语句,如果其路径与当前URL
匹配,则呈现其对应的组件<Route caseSensitive>
属性用于指定:匹配时是否区分大小写(默认为fasle
)- 当
URL
发生变化时,<Routes>
都会查看其所有子<Route>
元素以找到最佳匹配并呈现组件 <Route>
也可以嵌套使用,且配合useRoutes()
配置"路由表",但需要通过<Outlet>
组件来渲染其子路由(见<Outlet/>
说明)- 示例代码:
// 路由表
const element = useRoutes({
path: '/home',
element: <Home/>
},
{
path: '/about',
element: <About/>,
children: [
{
path: 'news',
element: <News/>,
},
{
path: 'message',
element: <Message/>,
children: [
{
path: 'detail',
element: <Detail/>
}
]
}
]
},
{
path: '/',
element: <Navigate to='/about'/>
}
])
return (
<>
{/* 1. 在react中靠路由实现切换组件--编写路由链接 */}
<NavLink className={okTive} to='/home'>Home</NavLink>
<br/>
<NavLink className={okTive} to='/about'>About</NavLink>
{/* 2. 注册路由 */}
<hr/>
{/* Routes注册*/}
{/* <Routes>
<Route path='/home' element={<Home/>} />
<Route path='/About' element={<About/>} />
<Route path='/' element={<Navigate to="/about"/>}/>
</Routes> */}
{/* 路由表注册*/}
{element}
</>
)
4. <Link>
- 作用:修改
URL
,且不发送网络请求(路由链接) - 注意: 外侧要用
<BrowserRouter/>
和<HashRouter/>
包裹
5. <NavLink>
- 作用:与
<Link>
组件类似,且可实现导航的高亮效果
6. <Navigate>
- 作用:只要
<Navigate>
组件被渲染,就会修改路径,切换视图 replace
属性用于控制跳转模式,(push
或replace
,默认是push
)- 实例代码:
import {useState} from 'react'
import {Navigate} from 'react-router-dom'
export default function Home() {
const [num, setNum] = useState(1)
return (
<>
{num === 2
? <Navigate to='/about' replace/>
: <h4>num的值是{num}</h4>}
<button onClick={() => setNum(2)}>点击</button>
</>
)
}
7. <Outlet>
- 当
<Route>
产生嵌套是,渲染其对应的后续子路由 - 示例代码:
<div>
<ul>
<li>
{/* <NavLink className={okTive} to='news'>News</NavLink> */}
{/* <NavLink className={okTive} to='/about/news'>News</NavLink> */}
<NavLink className={okTive} to='./news'>News</NavLink>
</li>
<li>
<NavLink className={okTive} to='message'>Message</NavLink>
</li>
</ul>
{/* 指定路由组件呈现的位置(二级+路由) */}
<Outlet/>
</div>
3. HOOKS
1. useRoutes()
- 根据路由表,动态创建
<Routes>
和<Route>
2. useNavigate()
- 作用:返回一个函数用来实现编程式导航
- 示例代码:
import { useNavigate } from 'react-router-dom'
export default function Hearder() {
const navigate = useNavigate()
const back = () => {
navigate(-1)
}
const forward = () => {
navigate(1)
}
const handleClick = () => {
navigate('detail',{
replace: false,
state: {
id: '122',
title: '小明',
content: '热爱祖国'
}
})
}
return (
<>
<button onClick={back}>后退</button>
<button onClick={forward}>前进</button>
<button onClick={handleClick}>跳转详情</button>
</>
)
}
3. useParams()
- 作用: 当前匹配路由的
params
参数
4. useSearchParams()
- 作用: 用于读取和修改当前位置的URL中的查询字符串
- 返回一个包含两个值的数组,内容分别为:当前的
search
参数、更新search
的函数
5. useLocation()
- 作用:获取当前
location
信息,对标5.x中的路由组件的localtion
属性(可用于获取state
参数)
6. useMatch()
- 作用:返回当前匹配信息,对标5.x中的路由组件的
match
属性
7. useInRouterContext()
(APP.jsx)
- 作用:如果组件在
<Router/>
的上下文中呈现(被路由包裹的组件),则useRouterContext
钩子返回true
,否则false
8. useNavigationType()
(News.jsx)
- 作用:返回当前的导航类型(用户是如何来到当前页面的)
- 返回值:
POP
,PUSH
,REPLACE
- 备注:
POP
是指在浏览器中直接打开了这个路由组件(刷新页面)
9. useOutlet()
(About.jsx)
- 作用:用来呈现当前组件中要渲染的嵌套路由
- 示例代码:
const a = useOutlet()
console.log(a, 'useOutlet嵌套')
// 如果嵌套路由没有挂载,则a为null
// 如果嵌套路由已经挂载,则展示嵌套路由对象
10. useResolvedPath()
(News.jsx)
- 作用:给定一个
URL
值,解析其中的:path
、search
、hash
值