React Router,客户端路由,可以将 URL 地址和 React 组件进行映射,当URL地址发生变化时,它会根据设置自动的切换到指定组件。
1 安装
npm install react-router-dom@6 -S
三个包
- react-router:核心库,提供了核心组件、钩子。
- react-router-dom:所有内容,并添加一些专门用于 DOM 的组件,例如
<BrowserRouter>等 - react-router-native:所有内容,并添加一些专门用于 ReactNative 的API,例如:
<NativeRouter>等。
2 组件
2.1 前置操作 <BrowserRouter> <HashRouter>
和 Redux 的 Provider 类似,要使得路由生效,需要使用<BrowserRouter>包裹整个 App 组件。
import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter } from "react-router-dom";
ReactDOM.render(
<BrowserRouter>
{/* 整体结构(通常为App组件) */}
</BrowserRouter>,root
);
<HashRouter>作用与<BrowserRouter>一样,但它修改的是地址栏的hash值(#后面的)。
2.2 注册路由 <Routes/> <Route/>
...
import { Link, Route, Routes } from 'react-router-dom';
const Home = ()=>{...};
const About = () => {...};
const App = () => {
return <div> App
<ul>
<li> <Link to='/'> home </Link> </li>
<li> <Link to='/about'>about</Link> </li>
</ul>
<Routes>
<Route path="/" element={<Home/>}/>
<Route path="/about" element={<About/>}/>
</Routes>
</div>;
};
Route 是路由的映射组件,将 url 和 React 组件进行映射。
- path —— 要匹配的路径
- element —— 路径匹配后挂载的组件
- index —— 布尔值,路由是否作为默认组件显示
Routes 是一个存放 Route 的容器。当浏览器的地址发生变化时,会自动对 Routes 中的所有 Route 进行匹配,匹配到的则显示,其余 Route 则不再继续匹配。
杂七杂八的属性
<Route caseSensitive>:匹配时是否区分大小写(默认 false)。
2.3 路由导航 <Link> <NavLink>
Link 组件生成超链接,点击后会修改浏览器地址栏的 url,但并不会真的向服务器发送请求。<Link to="/路径">按钮</Link>
NavLink 是特殊版本的 Link,可以根据不同的情况设置不同的样式。它可以设置如下属性:
- activeClassName —— 字符串,当链接被激活时为该链接添加指定的 CSS 类名
- activeStyle —— style 对象,当链接被激活时为该链接应用指定的样式
- isActive —— 函数,自定义判断链接是否激活的逻辑
- style —— 函数,动态设置链接的样式
- className —— 函数,动态设置链接的 class 值
<NavLink to="/home" activeClassName="active-link">Home</NavLink>
<NavLink to="/home" activeStyle={{ color: 'red' }}>Home</NavLink>
//isActive回调的默认参数是 match 和 location
<NavLink to="/home"
isActive={(match, location) => { match && location.pathname === '/home';}
>Home</NavLink>、
//className回调的默认参数为{isActive:true/false},表示该NavLink是否被激活
//我们直接用{isActive}解构拿到它
<NavLink to="login"
className = {
({ isActive }) => { return isActive ? 'xxx' : 'aaa'}
}
>login</NavLink>
<NavLink to="/home"
style={(match, location) => {color: match ? 'red' : 'blue'}
>Home</NavLink>
/*
默认情况下,当子组件匹配成功,父组件的导航也会高亮,
添加了end属性后,父组件不会再有高亮
*/
<NavLink to="home" end >home</NavLink>
2.4 重定向 <Navigate/>
将请求重定向到一个新的位置,经常用来进行权限的处理。例如:登录时则正常显示组件,未来登录时则跳转到登录页面。
{isLogin && <SomeAuthComponent/>}
{!isLogin && <Navigate to={"/login" replace={true}}></Redirect>}
上例中,如果 isLogin 的值为 true,表示用户已经登录,若用户登录,则挂载对应组件。
若isLogin值为false,则挂载 Navigate 组件触发重定向,重定向会使得路径跳转到登录页面。
- to —— 重定向的目标地址,可以是一个字符串也可以是一个对象
- from —— 需要重定向的地址
- push/replace —— 布尔值,是否使用 push/replace 方式对请求进行重定向,push 默认 true,replace 默认 false
3 路由表 Hook useRoutes()
step1 创建路由表
import About from '../pages/About'
import Home from '../pages/Home'
......
import {Navigate} from 'react-router-dom'
export default [
{
path:'/',
element:<Navigate to="/about"/>
},
{
path:'/about',
element:<About/>
},
{
path:'/home',
element:<Home/>,
children:[ //嵌套路由
{
path:'news',//不要写/news
element:<News/>
},
{
path:'message',
element:<Message/>,
}
]
}
]
Step2 注册路由
根据路由表生成对应的路由规则,即自动创建了<Routes>和<Route>。
import React from 'react'
import {NavLink,useRoutes} from 'react-router-dom'
import routes from './routes'
export default function App() {
//根据路由表生成对应的路由规则
const element = useRoutes(routes)
return (
<div>
......
{element}
{/* line12相当于生成下面这堆↓
<Routes>
<Route path="/home" element={<Home/>}/>
<Route path="/about" element={<About/>}/>
...
</Routes> */}
......
</div>
)
}
Step3 渲染路由组件
路由导航触发 url 更新以及渲染路由匹配到的组件。
//点击则渲染news和message两个子路由组件
<Link to="news">News</NavLink>
<Link to="message">Message</NavLink>
{/* 子路由组件呈现的位置 */}
<Outlet />
import React from 'react'
import {useNavigate} from 'react-router-dom'
export default function Demo() {
const navigate = useNavigate()
const handle = () => {
//法1:指定具体的路径和配置对象
//配置对象里只能配state参数,如果要用params和search,请直接拼在path里
navigate('/login', {
replace: false,
state: {a:1, b:2}
})
//法2:传入数值进行前进或后退
navigate(-1)
}
return (
<div><button onClick={handle}>按钮</button></div>
)
}
4 其他 Hook
4.1 useNavigate()
返回一个函数用来实现编程式路由导航。
一言以蔽之,取代掉 Link 和 NavLink,用来实现自动跳转等功能。
import React from 'react'
import {useNavigate} from 'react-router-dom'
export default function Demo() {
const navigate = useNavigate()
const handle = () => {
//法1:指定具体的路径和配置对象
//配置对象里只能配state参数,如果要用params和search,请直接拼在path里
navigate('/login', {
replace: false,
state: {a:1, b:2}
})
//法2:传入数值进行前进或后退
navigate(-1)
}
return (
<div><button onClick={handle}>按钮</button></div>
)
}
4.2 useParams()
返回当前匹配路由的params参数
① 在路由表中占位
export default [
{
path:'/about/:id/:title',
element:<About/>
},
② 触发路由更新时携带 params
...
<Link className="..."
to={`about/${m.id}/${m.title}`}>...
</Link>
③ 在组件中获取传过来的 params
let { id,title } = useParams();
4.3. useSearchParams()
search 参数和 params 参数不同,不需要占位。
返回一个包含两个值的数组,内容分别为:当前的seaech参数、更新search的函数。
import React from 'react'
import {useSearchParams} from 'react-router-dom'
export default function Detail() {
const [search,setSearch] = useSearchParams()
const id = search.get('id')
const title = search.get('title')
return (
<button onClick={()=>
setSearch('id=008&title=哈哈')}>
......
)
}
【补】search 参数、params 参数和 state 参数
- search 参数:通过 URL 查询字符串传递数据。
/path?param1=value1¶m2=value2
history.push({ search: '?param1=value1' })-- 编程路由导航<Link to={{ search: '?param1=value1' }}>Link</Link>
- params 参数:通过路由路径的占位符来传递数据。
/path/:param1/:param2
history.push('/path/value1/value2')<Link to="/path/value1/value2">Link</Link>
- state 参数:通过路由的 state 属性传递数据。一个对象,可以包含任意类型的数据。
history.push({ pathname: '/path', state: { data: 'value' } })<Link to={{ pathname: '/path', state: { data: 'value' } }}>Link</Link>
4.4. useLocation()
获取当前页面的位置信息——location 对象。
可以通过location 对象来获取 serach 和 state 参数。
import React from 'react'
import {useLocation} from 'react-router-dom'
export default function Detail() {
const x = useLocation()
console.log(x)
/*location对象:
{
hash: "", 当前页面URL的hash部分
key: "ah9nv6sz",
pathname: "/login",
search: "?name=zs&age=18",
state: {a: 1, b: 2}
}*/
//从location钩子返回的对象中解构出state参数
const {state:{id,title}} = useLocation()
return (
...
<li>{id}<li/>
<li>{title}<li/>
...
)
}
state 参数的传递
<Link className="..."
to="about"
state={{id:m.id,title:m.title}}
</Link>
4.5 useMatch()
检查当前页面的 URL 是否与指定的路径匹配。
line5:当前页面 url 是否和/login/:x/:y匹配,如不匹配,返回 null,如匹配,返回 match 对象。
match 对象用于获取与当前 URL 相关的信息
<Route path="/login/:page/:pageSize" element={<Login />}/>
<NavLink to="/login/1/10">登录</NavLink>
export default function Login() {
const match = useMatch('/login/:x/:y')
console.log(match) //输出match对象
/* match对象
{
params: {x: '1', y: '10'} URL中的动态路径参数相对应的键值对对象。
pathname: "/LoGin/1/10" 当前页面的url
pathnameBase: "/LoGin/" 省略了动态路径参数
pattern: { 与当前 URL 进行匹配的路由模式
path: '/login/:x/:y',
caseSensitive: false, 大小写是否敏感
end: false 路径是否必须以斜杠结束
}
}
*/
return (
...
)
}
【补】location 和 match 对象
两者都提供了有关 URL 的信息,但用途略有不同:
- match 对象用于确定 URL 是否与特定的路由模式匹配,并获取匹配成功后的动态路径参数等信息。帮助我们在组件中根据 URL 的匹配情况来执行不同的操作。
- location 对象主要用于获取当前页面的位置信息。帮助我们在组件中获取当前页面的 URL、路径、查询字符串等信息,并根据需要执行导航操作或其他页面相关的操作。
5 不常用 Hook
5.1 useInRouterContext()
如果组件在 <Router> 的上下文中呈现,则 useInRouterContext 钩子返回 true,否则返回 false。
用 BrowserRouter 包裹整个 App 组件,则 App 及其所有子组件就处于 Router 的上下文中。
5.2 useNavigationType()
返回当前的导航类型(用户是如何来到当前页面的)。
返回值:POP、PUSH、REPLACE。
备注:POP是指在浏览器中已经打开了这个路由组件,然后刷新了页面。
5.3 useOutlet()
用来呈现当前组件中渲染的嵌套路由组件。
const result = useOutlet()
console.log(result)
// 如果嵌套路由没有挂载,则result为null
// 如果嵌套路由已经挂载,则展示嵌套的路由对象
5.4 useResolvedPath()
给定一个 URL值,解析其中的:path、search、hash值。
6 React router5 和 6 的区别
-
内置组件的变化:移除
<Switch/>,新增<Routes/>等。 -
语法的变化:
component={About}变为element={<About/>}等。 -
新增多个hook:
useParams、useNavigate、useMatch等。 -
官方明确推荐函数式组件。