React Router
React Router 是 React 应用中用于管理路由的流行库,它允许你在单页应用(SPA)中实现导航和页面切换而无需重新加载页面。
安装
bash
npm install react-router-dom
核心组件
<BrowserRouter>
- 使用
HTML5
的历史记录API(pushState
、replaceState
和popstate
事件)来保持UI
与URL
的同步。 - 通常包裹在应用的根组件 中,提供基于浏览器历史记录的路由功能。
js
import { BrowserRouter } from 'react-router-dom'
function App(){
return (
<BrowserRouter >
{/* 其他组件 */}
</BrowserRouter >
)
}
<HashRouter>
- 通过监听浏览器的
hashchange
事件来检测路由变化,因为hash
部分不会被服务器解析,所以无需服务器支持。 - 使用方法和
BrowserRouter
一致,适合静态部署 或后端不支持history
路由的场景
<Routes>
和<Route>
<Routes>
:包裹所有路由规则<Route>
:定义单个路由,通过path
属性指定URL
路径、element
属性/component
属性指定要渲染的组件
js
import { Routes, Route } from 'react-router-dom'
function App() {
return (
<Routes>
<Route path="/" element={<Home />} />
</Routes>
);
}
<Link>
- 用于应用内导航,替代
<a>
标签实现导航,生成一个不会导致页面重新加载的链接,避免页面刷新
js
import { Link } from 'react-router-dom'
function Navbar() {
return (
<nav>
<Link to="/" >Home</Link>
</nav>
);
}
<Navigate>
- 用于编程式导航或重定向,例如:当用户访问某个路径时,可以自动重定向到另一个路径
js
<Route path="/old-path" element={<Navigate to="/new-path" />} />
动态路由
- 通过在路由
path
中使用冒号:参数名
定义参数
js
import { Route, Routes } from 'react-router-dom'
import User from './User'
<Routes>
// 这样 /user/123、/user/abc都会匹配该路由
<Route path="/user/:id" element={<User />} />
</Routes>
- 使用
*
通配符匹配任意路径
js
import { Route, Routes } from 'react-router-dom'
import User from './User'
<Routes>
// 这样 /user/xxx/yyy都会匹配该路由
<Route path="/user/*" element={<User />} />
</Routes>
获取URL参数
: 通过useParams
获取动态路径参数
js
import { useParams } from 'react-router-dom'
function User(){
const { id } = useParams()
return <div>用户ID:{id}</div>
}
获取查询参数
:通过useSearchParams
获取和修改查询参数
js
import { useSearchParams} from 'react-router-dom'
function SearchPage(){
const [searchParams, setSearchParams] = useSearchParams();
const keyword = searchParams.get("q"); // 例如 /search?q=react
return (
<input
value={keyword || ""}
onChange={(e) => setSearchParams({ q: e.target.value })}
/>
);
}
嵌套路由
- 在父路由中定义子路由,用
<Outlet>
指定子路由渲染位置
js
// 父组件---使用 <Outlet> 指定子组件的位置:
function Dashboard(){
return (
<div>
<h1>Dashboard</h1>
{/* 子路由内容在此渲染 */}
<Outlet />
</div>
)
}
// 通过 <Route> 的嵌套结构实现:
<Route path="/dashboard" element={<Dashboard />}>
<Route path="stats" element={<Stats />} />
<Route path="settings" element={<Settings />} />
</Route>
编程试导航
- 使用
useNavigate
钩子进行跳转
js
import { useNavigate } from "react-router-dom";
function LoginButton() {
const navigate = useNavigate();
return (
<button onClick={() => {
// 跳转到指定路径
navigate("/dashboard");
// 替换历史记录(无后退)
navigate("/dashboard", { replace: true });
// 带状态传递
navigate("/dashboard", { state: { from: "login" } });
}}>
Login
</button>
);
}
路由懒加载(代码分割)
- 使用
React.lazy
和Suspense
优化性能
js
import React, { lazy, Suspense } from 'react'
import { Routes, Route } from 'react-router-dom'
const Home = lazy(() => import('./home.jsx'))
function App(){
return (
// fallback属性可以自定义加载时的占位内容(如loading动画)
<Suspense fallback={<div>加载中。。。</div>}>
<Routes>
<Route path='/' element={<Home />}></Route>
</Routes>
</Suspense>
)
}
高阶组件实现权限控制
- 高阶组件是一种用于复用组件逻辑的高级技术;采用函数接收组件,返回新组件的模式。
js
function PrivateRoute({children}){
consr isAdmin = checkAuth()
return isAdmin ? children : <Navigate to='/login' />
}
<Route path='/admin' element={<PrivateRoute>
<Home />
</PrivateRoute>} />
数据加载(v6.4+)
- 使用
loader
和useLoaderData
在路由加载时预取数据
js
// 定义路由时配置loader
const router = createBrowserRouter([
{
path: '/user/:userId',
element: <User />
loader: async ({ params }) => {
// 根据URL传递的数据进行接口请求
const res = await fetch(`/api/users/${params.userId}`)
return res.json()
}
}
])
// 组件中获取数据
import { useLoaderData } from 'react-router-dom'
function User(){
// 直接获取 loader 返回的数据
const userData = useLoaderData();
return <div>{userData.name}</div>;
}
路由配置简单demo
- 在
src
目录下创建一个router
文件夹管理路由列表
js
// 用于编程式导航 重定向
import { Navigate } from 'react-router-dom'
// 高阶组件实现权限控制
import AuthRoute from '@/components/AuthRoute'
// 界面排版组件
import Layout from '@/pages/Layout'
import Admin from '@/pages/Admin'
import Login from '@/pages/Login'
export const routesList = [
{
path: '/',
element: <Navigate to="/home" />
},
{
path: '/login',
element: <Login />
},
{
path: '/admin',
element: <Admin />
children: [
{ { path: 'optical', element: <AuthRoute ><OpticalManage /></AuthRoute> }, }
]
},
]
- 在
App.tsx
进行路由配置
js
interface PageRoute{
path: string,
element: React.ReactNode,
children?: PageRoute[]
}
// 使用递归实现 Route 的渲染
function renderRoutes(routes: PageRoute[]) {
return routes.map(({ path, element, children }, index) => (
<Route key={path || index} path={path} element={element}>
{children && renderRoutes(children)}
</Route>
))
}
function App() {
const loading = useSelector<RootState, boolean>(state => state.head.loading)
return (
<div className="app-view">
{loading && <Loading />}
<Routes>
{ renderRoutes(routesList) }
</Routes>
</div>
)
}
export default App
常见坑
箭头函数体
用{}
时,必须显示写return
js
function renderRoutes(routes: PageRoute[]) {
return routes.map(({ path, element, children }, index) => {
return <Route key={path || index} path={path} element={element}>
{children && renderRoutes(children)}
</Route>
});
}
- 用
()
时,直接返回表达式
js
function renderRoutes(routes: PageRoute[]) {
return routes.map(({ path, element, children }, index) => (
<Route key={path || index} path={path} element={element}>
{children && renderRoutes(children)}
</Route>
))
}