eact-router官网:reactrouter.com/
2021年11月 react router 6 成为默认版本,npm安装时自动安装6版本
每次react router发布都会有3个版本
react-router : 路由的核心库,提供了很多组件钩子
react-router-dom: 包含react-douter所有内容,并添加了一些专门用于DOM的组件,例如BrowserRouter
react-router-native: 包含react-douter所有内容,并添加了一些专门用于ReactNative的一些api,例如Nativerouter
react router 6版本与5版本有哪些改动?
1、内置组件的变化:移除 新增Routers等
2、语法的变化:component={About} 变成 element={}
3、新增多个hook:useParams、useNavigate、useMatch
4、官方声明推荐函数式组件
一、路由模式选者
首先在入口文件index.js用BrowserRouter把App组件包裹住,代表用的是BrowserRouter,还有一种模式是hashRouter
index.js
import React from 'react'
import ReactDOM from 'react-dom/client'
import { BrowserRouter } from 'react-router-dom'
import App from './App'
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<BrowserRouter>
<App/>
</BrowserRouter>
)
二、一级路由 ----- 路由的基本使用 NavLink 、 Link、Routes、 Route:
Route必须由Routes包裹住,不包裹会报错,原来的Switch包裹是为了解决一直向下匹配的问题,用Routes包裹后也不存在这个问题
另外,Route的component={About}改成了 element={}
App.jsx
import React from 'react'
import { NavLink, Route, Routes } from 'react-router-dom'
import Home from './pages/Home'
import About from './pages/About'
import Demo from './pages/Demo'
import './App.css'
export default function App() {
return (
<div className="container">
<h1>react-router-dom-demo</h1>
<div className="main">
<aside className="aside">
{ /**
* 编写路由链接
* 在react中,靠路由连接切换组件
*/}
<NavLink className="btn" to="/home">home</NavLink>
<NavLink className="btn" to="/about">about</NavLink>
</aside>
<div className="content">
{/**
* 注册路由
*/}
<Routes>
{/* 路由匹配住/home后,不会再往下匹配 */}
<Route path="/home" element={<Home/>}></Route>
<Route path="/home" element={<Demo/>}></Route>
<Route path="/about" element={<About/>}></Route>
</Routes>
</div>
</div>
</div>
)
}
三、路由重定向 Navigate
当没有匹配任何路由的情况下,会有警告:No routes matched location "/"
5版本的重定向是使用Redirect:
6版本用Navigate组件,他有以下特性:
1、这个组件只要被渲染就会更改路径,切换路由
2、有一个replace属性,默认为false,为push模式,如果为true,就是replace模式(不会留下历史记录)
使用示例:
import { NavLink, Route, Routes, Navigate } from 'react-router-dom'
路由 / ,默认跳转到 /home路径
<Routes>
<Route path="/home" element={<Home/>}></Route>
<Route path="/about" element={<About/>}></Route>
<Route path="/" element={<Navigate to="/home"/>}></Route>
</Routes>
以下是通过条件判断,让路由切换
{ sum === 2 ? <Navigate to="/about"></Navigate> : <div>当前sum的值是: {sum}</div>}
四、Routes与Route
1、v6版本移除了,用Routes替代
2、Routes和Route要配合使用,必须用Routes包裹Route
3、Route相当于if语句,如果与当前URL匹配,就呈现对应组件
4、 用于指定:匹配时是否区分大小写,默认为false
5、当URL发生变化时,都会查其所有子以找到最佳匹配并呈现其页面
6、也可以嵌套使用,且可配合useRoutes()配置'路由表',但需要通过 组件来渲染子路由
五、NavLink高亮效果
5版本的NavLink高亮效果是组件内部会自动加上active类名,如果自定义高亮样式,可以加activeClassName,指定被选中的样式
6版本不支持activeClassName属性,router6要求,如果想自定义class类名,需要把className写成一个函数,返回类名
{ /**
* 编写路由链接
* 在react中,靠路由连接切换组件
*/}
<NavLink className={ ({isActive}) => isActive ? 'btn route_active' : 'btn' } to="/home">home</NavLink>
<NavLink className="btn" to="/about">about</NavLink>
嫌写的复杂了,可以提取出一个计算属性
function computedClassName({isActive}) {
return isActive ? 'btn route_active' : 'btn'
}
<NavLink className={ computedClassName } to="/home">home</NavLink>
<NavLink className={ computedClassName } to="/about">about</NavLink>
六、路由表的使用---useRoutes
我们把下面这个写成一个路由表,路由表必须是个数组
===》
import { NavLink, Route, Routes, Navigate, useRoutes } from 'react-router-dom'
const element = useRoutes([
{
path: '/home',
element: <Home/>
},
{
path: '/about',
element: <About/>
},
{
path: '/',
element: <Navigate to="/home"/>
}
])
{/**
* 注册路由
*/}
{/* <Routes>
<Route path="/home" element={<Home/>}></Route>
<Route path="/ab0ut" element={<About/>}></Route>
<Route path="/" element={<Navigate to="/home"/>}></Route>
</Routes> */}
取而代之
{element}
一般路由表会专门用一个文件来写
routes/index.js
import { Navigate } from 'react-router-dom'
import Home from '../pages/Home'
import About from '../pages/About'
const routes = [
{
path: '/home',
element: <Home/>
},
{
path: '/about',
element: <About/>
},
{
path: '/',
element: <Navigate to="/home"/>
}
]
export default routes
页面中引入使用:
import { NavLink, useRoutes } from 'react-router-dom'
import routes from './routes'
// 根据路由表生成对应的路由规则
const element = useRoutes(routes);
七、嵌套路由
router6的路由表统一在routes文件下配置,那么子路由就需要一个槽位来指定子路由显示的位置,这个标签是outlet,相当于vue中的router-view,
配置嵌套路由表:
routes/index.js
import { Navigate } from 'react-router-dom'
import Home from '../pages/Home'
import About from '../pages/About'
import News from '../pages/News'
import Message from '../pages/Message'
const routes = [
{
path: '/home',
element: <Home/>,
children: [
{
path: 'news',
element: <News/>
},
{
path: '/home/message',
element: <Message/>
},
]
},
{
path: '/about',
element: <About/>
},
{
path: '/',
element: <Navigate to="/home"/>
}
]
export default routes
用Outlet指定子路由在页面中显示的位置:
import { Outlet } from 'react-router-dom';
{<Outlet/>}
另外一个小知识点,当切换到子路由时,对应的父级路由也会高亮,在父级路由的NavLink上加上end属性,可以不让其高亮
<NavLink className={ computedClassName } end to="/home">home</NavLink>
八、路由传参
(1)、params传参:接收参数时使用useParams函数
路由表里定义params参数
{
path: '/home/message',
element: <Message/>,
children: [
{
path: 'detail/:id/:title/:content',
element: <Detail/>
}
]
}
路由跳转时传入参数
messages.map(m => {
return <li key={m.id}>
<Link to={`detail/${m.id}/${m.title}/${m.content}`}>{m.title}</Link>
</li>
})
接收路由params参数,需要用到useParams()
import { useParams } from 'react-router-dom'
const params = useParams();
也可以用useMatch()
import { useMatch } from 'react-router-dom'
const a = useMatch('/home/message/detail/:id/:title/:content');
(2)、search传参
需要用useSearchParams()接收参数
search传参:
messages.map(m => {
return <li key={m.id}>
<Link to={`detail?id=${m.id}&title=${m.title}&content=${m.content}`}>{m.title}</Link>
</li>
})
接收参数:useSearchParams()
import React from 'react'
import { useParams, useMatch, useSearchParams } from 'react-router-dom'
export default function Detail() {
const [search, setSearch] = useSearchParams();
const id = search.get('id');
const title = search.get('title');
const content = search.get('content');
return (
<ul>
<button onClick={ () => setSearch('id=008&title=嘻嘻&content=哈哈') }>点我更改search参数</button>
<li>id:{id}</li>
<li>title:{title}</li>
<li>content:{content}</li>
</ul>
)
}
也可以用useLocation()接收
import { useLocation } from 'react-router-dom'
const x = useLocation();
(3)、state传参:
传参:
messages.map(m => {
return <li key={m.id}>
<Link to="detail" state={{ id: m.id, title: m.title, content: m.content }}>{m.title}</Link>
</li>
})
接收参数,使用useLocation()
import { useLocation } from 'react-router-dom'
const {state} = useLocation();
九、编程式导航:
需要用到useNavigate()
在router5中,普通组件想使用路由里的location、match、history,需要用withRouter(组件)加工一下,但router6不需要,可以直接用钩子函数就可以使用router的任何东西
const navigate = useNavigate();
路由跳转、传参
// search、params传参直接在路径中传参,state在第二个参数里传
navigate('detail',{
replace: false,
state: {
id:m.id,
title:m.title,
content:m.content,
}
})
前进、后退
navigate(1) // 前进
navigate(-1) // 后退
十、useInRouterContext()
作用:如果组件在的上下文中呈现,则useInRouterContext()返回true,否则返回false
被BrowserRouter或HashRouter包裹住的就是在路由环境中
import { useInRouterContext } from 'react-router-dom'
console.log(useInRouterContext());
十一、useNavigationType()
作用:返回当前导航类型(用户是如何来到当前页面的)
返回值:POP、PUSH、REPLACE
备注:POP是指在浏览器中直接打开这个路由组件(刷新页面)
import { useNavigationType } from 'react-router-dom'
const type = useNavigationType();
十二、useOutlet
作用:用来呈现当前组件中渲染的嵌套路由
import { useOutlet } from 'react-router-dom'
const childRoute = useOutlet();
// 如果嵌套路由没有挂载,childRoute返回null
// 如果嵌套路由已挂载,返回渲染的路由对象
十三、useResolvedPath()
作用:给一个URL值,解析期中的path、search、hash
import { useResolvedPath } from 'react-router-dom'
useResolvedPath('/user?id=001&name=tom#qwe')