React Router 路由导航
React Router 是 React 最流行的路由库,用于构建单页应用(SPA)的导航系统。
警告
本教程基于 React Router v6,官方文档
安装
bash
npm install react-router-dom
# 或使用 pnpm
pnpm add react-router-dom
# 或使用 yarn
yarn add react-router-dom基础使用
1. 配置路由
jsx
import {BrowserRouter, Routes, Route} from "react-router-dom";
import Home from "./pages/Home";
import About from "./pages/About";
import Contact from "./pages/Contact";
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/contact" element={<Contact />} />
</Routes>
</BrowserRouter>
);
}
export default App;2. 导航链接
使用 Link 组件进行导航:
jsx
import {Link} from "react-router-dom";
function Navigation() {
return (
<nav>
<Link to="/">首页</Link>
<Link to="/about">关于</Link>
<Link to="/contact">联系</Link>
</nav>
);
}
export default Navigation;3. 编程式导航
使用 useNavigate Hook 进行编程式导航:
jsx
import {useNavigate} from "react-router-dom";
function Home() {
const navigate = useNavigate();
const handleClick = () => {
navigate('/about');
// 或 navigate('/about', { replace: true });
};
return (
<div>
<h1>首页</h1>
<button onClick={handleClick}>跳转到关于页面</button>
</div>
);
}
export default Home;路由参数
1. URL 参数(useParams)
jsx
import {Routes, Route, useParams} from "react-router-dom";
// 定义带参数的路由
function App() {
return (
<Routes>
<Route path="/user/:id" element={<UserProfile />} />
<Route path="/post/:category/:slug" element={<PostDetail />} />
</Routes>
);
}
// 获取 URL 参数
function UserProfile() {
const {id} = useParams();
return <div>用户 ID: {id}</div>;
}
function PostDetail() {
const {category, slug} = useParams();
return (
<div>
<p>分类: {category}</p>
<p>标题: {slug}</p>
</div>
);
}2. 查询参数(useSearchParams)
jsx
import {useSearchParams} from "react-router-dom";
function Search() {
const [searchParams, setSearchParams] = useSearchParams();
// 获取查询参数
const keyword = searchParams.get('keyword');
const page = searchParams.get('page') || '1';
const handleSearch = (newKeyword) => {
// 更新查询参数
setSearchParams({keyword: newKeyword, page: '1'});
};
return (
<div>
<input
value={keyword || ''}
onChange={(e) => handleSearch(e.target.value)}
/>
<p>当前页码: {page}</p>
</div>
);
}嵌套路由
1. 使用 Outlet
jsx
import {Routes, Route, Outlet, Link} from "react-router-dom";
function Layout() {
return (
<div>
<nav>
<Link to="/dashboard">仪表盘</Link>
<Link to="/dashboard/profile">个人资料</Link>
<Link to="/dashboard/settings">设置</Link>
</nav>
<Outlet /> {/* 子路由会在这里渲染 */}
</div>
);
}
function App() {
return (
<Routes>
<Route path="/dashboard" element={<Layout />}>
<Route index element={<Dashboard />} />
<Route path="profile" element={<Profile />} />
<Route path="settings" element={<Settings />} />
</Route>
</Routes>
);
}2. 嵌套路由配置示例
jsx
function Dashboard() {
return <div>仪表盘首页</div>;
}
function Profile() {
return <div>个人资料页面</div>;
}
function Settings() {
return <div>设置页面</div>;
}路由守卫
1. 受保护的路由
jsx
import {Navigate, Outlet} from "react-router-dom";
function ProtectedRoute({isAuthenticated}) {
if (!isAuthenticated) {
return <Navigate to="/login" replace />;
}
return <Outlet />;
}
function App() {
const isAuthenticated = true; // 从状态管理或 Context 获取
return (
<Routes>
<Route path="/login" element={<Login />} />
<Route element={<ProtectedRoute isAuthenticated={isAuthenticated} />}>
<Route path="/dashboard" element={<Dashboard />} />
<Route path="/profile" element={<Profile />} />
</Route>
</Routes>
);
}2. 重定向
jsx
import {Navigate} from "react-router-dom";
function App() {
return (
<Routes>
<Route path="/" element={<Navigate to="/home" replace />} />
<Route path="/home" element={<Home />} />
</Routes>
);
}路由匹配
1. 精确匹配
jsx
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="*" element={<NotFound />} /> {/* 404 页面 */}
</Routes>2. 通配符路由
jsx
<Routes>
<Route path="/blog/*" element={<BlogLayout />}>
<Route path=":slug" element={<BlogPost />} />
</Route>
</Routes>路由钩子
1. useLocation
获取当前路由位置信息:
jsx
import {useLocation} from "react-router-dom";
function CurrentLocation() {
const location = useLocation();
return (
<div>
<p>路径: {location.pathname}</p>
<p>查询: {location.search}</p>
<p>哈希: {location.hash}</p>
<p>状态: {JSON.stringify(location.state)}</p>
</div>
);
}2. useNavigate
编程式导航:
jsx
import {useNavigate} from "react-router-dom";
function NavigationExample() {
const navigate = useNavigate();
return (
<div>
<button onClick={() => navigate('/about')}>前进</button>
<button onClick={() => navigate(-1)}>后退</button>
<button onClick={() => navigate(1)}>前进</button>
<button onClick={() => navigate('/home', {replace: true})}>
替换当前历史记录
</button>
<button onClick={() => navigate('/user/123', {state: {from: 'home'}})}>
带状态导航
</button>
</div>
);
}3. useNavigationType
获取导航类型:
jsx
import {useNavigationType} from "react-router-dom";
function NavigationInfo() {
const type = useNavigationType(); // POP, PUSH, REPLACE
return <div>导航类型: {type}</div>;
}NavLink 组件
NavLink 可以在当前路由匹配时添加样式:
jsx
import {NavLink} from "react-router-dom";
function Navigation() {
return (
<nav>
<NavLink
to="/"
className={({isActive}) => isActive ? 'active' : ''}
>
首页
</NavLink>
<NavLink
to="/about"
style={({isActive}) => ({
color: isActive ? 'red' : 'black'
})}
>
关于
</NavLink>
</nav>
);
}懒加载路由
jsx
import {lazy, Suspense} from "react";
import {Routes, Route} from "react-router-dom";
const Home = lazy(() => import('./pages/Home'));
const About = lazy(() => import('./pages/About'));
function App() {
return (
<Suspense fallback={<div>加载中...</div>}>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
</Routes>
</Suspense>
);
}路由配置对象
可以使用配置对象的方式定义路由:
jsx
import {useRoutes} from "react-router-dom";
const routeConfig = [
{
path: '/',
element: <Layout />,
children: [
{index: true, element: <Home />},
{path: 'about', element: <About />},
{path: 'contact', element: <Contact />},
]
},
{
path: '*',
element: <NotFound />
}
];
function App() {
const routes = useRoutes(routeConfig);
return routes;
}常见场景
1. 登录后跳转
jsx
import {useNavigate, useLocation} from "react-router-dom";
function Login() {
const navigate = useNavigate();
const location = useLocation();
const handleLogin = () => {
// 登录逻辑...
// 跳转到登录前的页面,或默认跳转到首页
const from = location.state?.from?.pathname || '/dashboard';
navigate(from, {replace: true});
};
return <button onClick={handleLogin}>登录</button>;
}2. 路由动画
jsx
import {Routes, Route, useLocation} from "react-router-dom";
import {AnimatePresence, motion} from "framer-motion";
function App() {
const location = useLocation();
return (
<AnimatePresence mode="wait">
<Routes location={location} key={location.pathname}>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
</Routes>
</AnimatePresence>
);
}3. 面包屑导航
jsx
import {useMatches} from "react-router-dom";
function Breadcrumbs() {
const matches = useMatches();
return (
<nav>
{matches.map((match, index) => (
<span key={match.pathname}>
{index > 0 && ' / '}
{match.pathname || '首页'}
</span>
))}
</nav>
);
}最佳实践
- 使用 BrowserRouter 而非 HashRouter(SEO 友好)
- 合理使用嵌套路由,避免路由结构过深
- 路由懒加载提升首屏加载速度
- 统一路由守卫,集中管理权限控制
- 使用 TypeScript增强路由类型安全
Router 类型
BrowserRouter vs HashRouter
jsx
import {BrowserRouter, HashRouter} from "react-router-dom";
// BrowserRouter: 使用 HTML5 History API
// URL: http://example.com/about
<BrowserRouter>
<App />
</BrowserRouter>
// HashRouter: 使用 URL hash
// URL: http://example.com/#/about
<HashRouter>
<App />
</HashRouter>最后更新:2025年