Appearance
React 路由
React Router 是 React 官方推荐的路由库,它允许我们在 React 应用中实现单页面应用(SPA)的导航功能。本章节将介绍 React Router v6 的基本使用方法。
10.1 什么是路由?
路由的定义
路由是指根据 URL 的变化来展示不同的页面内容。在单页面应用(SPA)中,路由可以实现页面的切换而不需要刷新整个页面。
单页面应用(SPA)原理
- 传统多页面应用:每次导航都会请求新的 HTML 页面
- 单页面应用:只加载一个 HTML 页面,通过 JavaScript 动态更新内容
- 优势:更快的页面切换速度,更好的用户体验
10.2 React Router v6 安装与配置
安装
bash
npm install react-router-dom基本配置
jsx
// src/App.jsx
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import Home from './pages/Home';
import About from './pages/About';
import NotFound from './pages/NotFound';
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="*" element={<NotFound />} />
</Routes>
</BrowserRouter>
);
}
export default App;10.3 核心组件使用
BrowserRouter
BrowserRouter 是 React Router 的根组件,它使用 HTML5 的 History API 来管理路由。
jsx
import { BrowserRouter } from 'react-router-dom';
function App() {
return (
<BrowserRouter>
{/* 路由配置 */}
</BrowserRouter>
);
}Routes 和 Route
Routes 是路由容器,Route 定义单个路由规则。
jsx
import { Routes, Route } from 'react-router-dom';
function App() {
return (
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/users/:id" element={<User />} />
<Route path="*" element={<NotFound />} />
</Routes>
);
}Link 和 NavLink
Link 用于创建导航链接,NavLink 是 Link 的增强版,支持激活状态。
jsx
import { Link, NavLink } from 'react-router-dom';
function Navigation() {
return (
<nav>
<Link to="/">首页</Link>
<Link to="/about">关于</Link>
<NavLink to="/contact" activeClassName="active">
联系我们
</NavLink>
</nav>
);
}10.4 路由参数
动态路由参数
jsx
// 路由配置
<Route path="/users/:id" element={<User />} />
// 组件中获取参数
import { useParams } from 'react-router-dom';
function User() {
const { id } = useParams();
return <h1>用户 ID:{id}</h1>;
}查询参数
jsx
// 跳转到带查询参数的路由
import { Link, useNavigate } from 'react-router-dom';
function Home() {
const navigate = useNavigate();
function goToSearch() {
navigate('/search?keyword=React&page=1');
}
return (
<div>
<Link to="/search?keyword=React&page=1">搜索 React</Link>
<button onClick={goToSearch}>搜索 React</button>
</div>
);
}
// 组件中获取查询参数
import { useSearchParams } from 'react-router-dom';
function Search() {
const [searchParams, setSearchParams] = useSearchParams();
const keyword = searchParams.get('keyword');
const page = searchParams.get('page');
function changePage(newPage) {
setSearchParams({ keyword, page: newPage });
}
return (
<div>
<p>关键词:{keyword}</p>
<p>页码:{page}</p>
<button onClick={() => changePage(2)}>第 2 页</button>
</div>
);
}10.5 嵌套路由
嵌套路由允许我们在父路由中定义子路由,实现页面的嵌套布局。
jsx
// 路由配置
<Route path="/dashboard" element={<Dashboard />}>
<Route index element={<DashboardHome />} />
<Route path="profile" element={<Profile />} />
<Route path="settings" element={<Settings />} />
</Route>
// Dashboard 组件
import { Outlet, Link } from 'react-router-dom';
function Dashboard() {
return (
<div>
<h1>仪表盘</h1>
<nav>
<Link to="/dashboard">首页</Link>
<Link to="/dashboard/profile">个人资料</Link>
<Link to="/dashboard/settings">设置</Link>
</nav>
<Outlet /> {/* 子路由内容将在这里渲染 */}
</div>
);
}10.6 路由重定向
使用 Navigate 组件实现路由重定向。
jsx
import { Navigate } from 'react-router-dom';
// 重定向到首页
<Route path="/old-home" element={<Navigate to="/" replace />} />
// 条件重定向
function ProtectedRoute({ children }) {
const isLoggedIn = false; // 实际应用中应该从状态管理中获取
if (!isLoggedIn) {
return <Navigate to="/login" replace />;
}
return children;
}
// 使用
<Route path="/dashboard" element={<ProtectedRoute><Dashboard /></ProtectedRoute>} />10.7 404页面配置
使用通配符 * 来匹配未定义的路由,实现 404 页面。
jsx
<Route path="*" element={<NotFound />} />
// NotFound 组件
function NotFound() {
return (
<div>
<h1>404</h1>
<p>页面未找到</p>
<Link to="/">返回首页</Link>
</div>
);
}10.8 编程式导航
使用 useNavigate 钩子实现编程式导航。
jsx
import { useNavigate } from 'react-router-dom';
function LoginForm() {
const navigate = useNavigate();
function handleSubmit() {
// 登录逻辑
navigate('/dashboard');
}
function goBack() {
navigate(-1); // 后退一步
}
function goForward() {
navigate(1); // 前进一步
}
return (
<div>
<form onSubmit={handleSubmit}>
{/* 表单内容 */}
<button type="submit">登录</button>
</form>
<button onClick={goBack}>返回</button>
<button onClick={goForward}>前进</button>
</div>
);
}10.9 路由守卫
简单的路由守卫
jsx
import { Navigate, useLocation } from 'react-router-dom';
function RequireAuth({ children }) {
const isLoggedIn = false; // 实际应用中应该从状态管理中获取
const location = useLocation();
if (!isLoggedIn) {
// 保存当前位置,登录后可以重定向回来
return <Navigate to="/login" state={{ from: location }} replace />;
}
return children;
}
// 使用
<Route path="/dashboard" element={<RequireAuth><Dashboard /></RequireAuth>} />
// 登录组件
import { useNavigate, useLocation } from 'react-router-dom';
function Login() {
const navigate = useNavigate();
const location = useLocation();
const from = location.state?.from || '/';
function handleLogin() {
// 登录逻辑
navigate(from, { replace: true });
}
return (
<form onSubmit={handleLogin}>
{/* 表单内容 */}
<button type="submit">登录</button>
</form>
);
}实战练习
练习1:基本路由配置
jsx
// src/App.jsx
import { BrowserRouter, Routes, Route, Link } from 'react-router-dom';
import Home from './pages/Home';
import About from './pages/About';
import Contact from './pages/Contact';
import NotFound from './pages/NotFound';
function App() {
return (
<BrowserRouter>
<nav>
<Link to="/">首页</Link>
<Link to="/about">关于</Link>
<Link to="/contact">联系我们</Link>
</nav>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/contact" element={<Contact />} />
<Route path="*" element={<NotFound />} />
</Routes>
</BrowserRouter>
);
}
export default App;
// src/pages/Home.jsx
function Home() {
return <h1>首页</h1>;
}
export default Home;
// src/pages/About.jsx
function About() {
return <h1>关于我们</h1>;
}
export default About;
// src/pages/Contact.jsx
function Contact() {
return <h1>联系我们</h1>;
}
export default Contact;
// src/pages/NotFound.jsx
import { Link } from 'react-router-dom';
function NotFound() {
return (
<div>
<h1>404</h1>
<p>页面未找到</p>
<Link to="/">返回首页</Link>
</div>
);
}
export default NotFound;练习2:嵌套路由
jsx
// src/App.jsx
import { BrowserRouter, Routes, Route, Link, Outlet } from 'react-router-dom';
import Home from './pages/Home';
import About from './pages/About';
import Dashboard from './pages/Dashboard';
import DashboardHome from './pages/DashboardHome';
import Profile from './pages/Profile';
import Settings from './pages/Settings';
import NotFound from './pages/NotFound';
function App() {
return (
<BrowserRouter>
<nav>
<Link to="/">首页</Link>
<Link to="/about">关于</Link>
<Link to="/dashboard">仪表盘</Link>
</nav>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/dashboard" element={<Dashboard />}>
<Route index element={<DashboardHome />} />
<Route path="profile" element={<Profile />} />
<Route path="settings" element={<Settings />} />
</Route>
<Route path="*" element={<NotFound />} />
</Routes>
</BrowserRouter>
);
}
export default App;
// src/pages/Dashboard.jsx
import { Link, Outlet } from 'react-router-dom';
function Dashboard() {
return (
<div>
<h1>仪表盘</h1>
<nav>
<Link to="/dashboard">首页</Link>
<Link to="/dashboard/profile">个人资料</Link>
<Link to="/dashboard/settings">设置</Link>
</nav>
<Outlet />
</div>
);
}
export default Dashboard;
// src/pages/DashboardHome.jsx
function DashboardHome() {
return <h2>仪表盘首页</h2>;
}
export default DashboardHome;
// src/pages/Profile.jsx
function Profile() {
return <h2>个人资料</h2>;
}
export default Profile;
// src/pages/Settings.jsx
function Settings() {
return <h2>设置</h2>;
}
export default Settings;练习3:路由参数和查询参数
jsx
// src/App.jsx
import { BrowserRouter, Routes, Route, Link } from 'react-router-dom';
import Home from './pages/Home';
import User from './pages/User';
import Search from './pages/Search';
import NotFound from './pages/NotFound';
function App() {
return (
<BrowserRouter>
<nav>
<Link to="/">首页</Link>
<Link to="/user/1">用户 1</Link>
<Link to="/user/2">用户 2</Link>
<Link to="/search?keyword=React">搜索 React</Link>
</nav>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/user/:id" element={<User />} />
<Route path="/search" element={<Search />} />
<Route path="*" element={<NotFound />} />
</Routes>
</BrowserRouter>
);
}
export default App;
// src/pages/User.jsx
import { useParams } from 'react-router-dom';
function User() {
const { id } = useParams();
return <h1>用户 ID:{id}</h1>;
}
export default User;
// src/pages/Search.jsx
import { useSearchParams } from 'react-router-dom';
function Search() {
const [searchParams, setSearchParams] = useSearchParams();
const keyword = searchParams.get('keyword');
const page = searchParams.get('page') || 1;
function changePage(newPage) {
setSearchParams({ keyword, page: newPage });
}
return (
<div>
<h1>搜索结果</h1>
<p>关键词:{keyword}</p>
<p>页码:{page}</p>
<button onClick={() => changePage(1)}>第 1 页</button>
<button onClick={() => changePage(2)}>第 2 页</button>
<button onClick={() => changePage(3)}>第 3 页</button>
</div>
);
}
export default Search;通过本章节的学习,你已经掌握了 React Router v6 的基本使用方法。React Router 是构建单页面应用的核心工具,掌握它对于开发现代 React 应用至关重要。
