主题
React Router
介绍
React Router 是一个用于处理路由的库,它提供了一套用于处理路由的组件和 API,使得在 React 应用中实现路由功能更加方便和灵活。
安装
bash
npm i react-router-dom详细说明
- v17 -> react-router-dom@5
- v18 -> react-router-dom@6
- v19 -> react-router-dom@7
项目搭建
bash
/src
/router
index.jsx
App.jsx
main.jsxjsx
import { createHashRouter } from 'react-router-dom'
import React, { Suspense } from 'react'
import Home from '../views/Home.jsx'
const About = React.lazy(() => import('../views/About.jsx'))
const router = createHashRouter([
{
path: '/',
element: <Home />,
},
{
path: '/about',
element: (
<Suspense fallback={<div>Loading...</div>}>
<About />
</Suspense>
),
},
])
export default routerjsx
import { RouterProvider } from 'react-router-dom'
import router from './router'
function App() {
return <RouterProvider router={router}></RouterProvider>
}
export default App路由懒加载
如上,使用 React.lazy 引入组件,还可以使用 Suspense 包裹,指定 fallback 为加载提示组件。
路由模式
常见的路由模式:
- HTML5 模式:例如
/home。且需后端支持。 - Hash 模式:例如
/#/home。兼容性最好。 - Memory 模式:适用于非浏览器环境(如 React Native)。
- Static 模式:适用于服务端渲染(SSR)。
jsx
import { createBrowserRouter, createHashRouter, createMemoryRouter, createStaticRouter } from 'react-router-dom'
const router = createBrowserRouter([
// ...
])jsx
import { BrowserRouter, HashRouter, MemoryRouter, StaticRouter } from 'react-router-dom
function App() {
return (
<BrowserRouter>
{/* ... */}
</BrowserRouter>
)
}创建路由
Data Router
createBrowserRouter + <RouterProvider>
jsx
import { createBrowserRouter, RouterProvider } from 'react-router-dom'
// 或者 createHashRouter, createMemoryRouter
const router = createBrowserRouter(
[
// ...
],
{
basename: '/app', // 可选,路由基路径
},
)
function App() {
return <RouterProvider router={router} />
}UI Router
<BrowserRouter> + <Routes>
jsx
import { BrowserRouter, Routes, Route } from 'react-router-dom'
import Home from './views/Home'
import About from './views/About'
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
</Routes>
</BrowserRouter>
)
}<BrowserRouter> + useRoutes
jsx
import { BrowserRouter, useRoutes } from 'react-router-dom'
function AppRoutes() {
const routes = useRoutes([
// ...
])
return routes
}
function App() {
return (
<BrowserRouter>
<AppRoutes />
</BrowserRouter>
)
}路由导航
声明式
常见三种组件:
<Link>:基础跳转。<NavLink>:导航跳转(支持高亮)。<Navigate>:自动重定向。
jsx
import { Link, NavLink, Navigate } from 'react-router-dom'
function Home() {
return (
<div>
{/* 普通跳转 */}
<Link to="/about">关于页</Link>
{/* 导航跳转(支持高亮) */}
<NavLink to="/about" className={({ isActive }) => (isActive ? 'active' : '')}>
关于页
</NavLink>
{/* 自动重定向 */}
<Navigate to="/about" replace />
</div>
)
}
export default Home编程式
常使用 useNavigate 钩子实现编程式导航:
jsx
import { useNavigate } from 'react-router-dom'
function Home() {
const navigate = useNavigate()
return (
<div>
<h1>Home</h1>
<button onClick={() => navigate('/about')}>关于页</button>
</div>
)
}
export default Home路由接收参数
search params
jsx
// 如:/user?id=12&name=vfanlee
import { useSearchParams } from 'react-router-dom'
const [params] = useSearchParams()
const id = params.get('id')
const name = params.get('name')path params
jsx
// 如:/user/:id/:name
import { useParams } from 'react-router-dom'
const params = useParams()
const id = params.id
const name = params.name路由激活
<NavLink>
<NavLink> 会自动为当前激活的链接添加 active 类:
jsx
import { NavLink } from 'react-router-dom'
function Navbar() {
return (
<nav>
<NavLink to="/home" className={({ isActive }) => (isActive ? 'active' : '')}>
Home
</NavLink>
<NavLink to="/about" className={({ isActive }) => (isActive ? 'active' : '')}>
About
</NavLink>
</nav>
)
}useMatch
如果你用的是动态路径,比如 /users/:id,可以使用 useMatch 来匹配当前路由:
jsx
import { useMatch, Link } from 'react-router-dom'
function Navbar() {
const match = useMatch('/users/:id')
return (
<Link to="/users/123" className={match ? 'active' : ''}>
User Detail
</Link>
)
}useLocation
使用 useLocation 获取当前路径名,再手动判断:
注意:
location.pathname是完整路径,不带 query 或 hash。
jsx
import { useLocation, Link } from 'react-router-dom'
function Navbar() {
const location = useLocation()
return (
<nav>
<Link to="/home" className={location.pathname === '/home' ? 'active' : ''}>
Home
</Link>
<Link to="/about" className={location.pathname === '/about' ? 'active' : ''}>
About
</Link>
</nav>
)
}路由配置
以 createBrowserRouter 为例。
basename
basename 用于指定路由的基路径:
jsx
const router = createBrowserRouter(
[
// ...
],
{
// 所有路由都会以 /app 开头
basename: '/app',
},
)配置项
path:路由路径。element:路由对应的组件。children:子路由配置数组。index:是否为默认路由。errorElement:加载出错时显示的组件。loader:数据加载函数。action:表单提交处理函数。handle:自定义路由句柄,可用于传递任意数据。
动态路由
jsx
{
path: '/users/:id',
element: <UserDetail />
}匹配 404
jsx
{
path: '*',
element: <NotFound />
}嵌套路由
- 在路由配置文件中通过
children属性配置子路由 - 在父组件中通过
<Outlet>组件渲染子路由
jsx
{
path: '/',
element: <Layout />,
children: [
{
path: '/home',
element: <Home />
},
{
path: '/about',
element: <About />
}
]
}jsx
import { Outlet } from 'react-router-dom'
function Layout() {
return (
<>
<sidebar>这是侧边栏</sidebar>
<div>
<header>这是头部</header>
<main>
<Outlet />
</main>
<footer>这是底部</footer>
</div>
</>
)
}
export default Layout默认路由
嵌套路由时,指定某个子路由为默认路由,可通过 index: true 指定默认路由:
jsx
{
path: '/',
element: <Layout />,
children: [
{
index: true,
element: <Home />
},
{
path: '/about',
element: <About />
}
]
}jsx
{
path: '/',
element: <Layout />,
children: [
{
path: '',
element: <Home />
},
{
path: '/about',
element: <About />
}
]
}loading 和 error
jsx
import { Suspense } from 'react'
const router = createBrowserRouter([
{
path: '/about',
// 使用 Suspense 包裹异步组件,实现加载状态
element: (
<Suspense fallback={<div>Loading...</div>}>
<About />
</Suspense>
),
// 加载出错时显示的组件
errorElement: <div>加载出错了!</div>,
},
])loader
jsx
import { redirect } from 'react-router-dom'
export async function authLoader() {
const isLogin = Boolean(localStorage.getItem('token'))
if (!isLogin) {
throw redirect('/login')
}
return null
}
const router = createBrowserRouter([
{
path: '/login',
element: <Login />,
},
{
path: '/',
element: <Layout />,
loader: authLoader, // 路由级拦截
children: [
{
path: 'dashboard',
element: <Dashboard />,
},
],
},
])action
只有在使用 <Form> 组件提交表单时,才会触发对应路由的 action 函数。
略。
handle
类似于 route meta,可以在路由对象上存储任意数据,供组件或钩子函数使用。
jsx
const router = createBrowserRouter([
{
path: '/admin',
element: <Admin />,
handle: {
auth: true,
role: 'admin',
title: '后台管理',
},
},
])如何读取?
jsx
import { useMatches } from 'react-router-dom'
const matches = useMatches()
const currentRoute = matches[matches.length - 1]
console.log(currentRoute.handle)