React Router 路由
到目前为止我们写的都是单页应用,URL 永远是 /。真实项目需要多个页面:首页、关于、用户列表、文章详情。React 本身不带路由(它只是个 UI 库),但社区有事实标准库 React Router。这一章我们学会用它做多页应用。
1. 为什么需要路由
传统的多页网站,点链接会整页刷新——服务器返回新 HTML,浏览器重新加载所有资源,体验差。单页应用(SPA)的做法是:整个应用只有一个 HTML,点链接时用 JS 切换显示的内容,不刷新页面,体验丝滑。但要解决两个问题:URL 要变(方便分享、收藏)、浏览器前进后退要工作——这就是路由干的事。
2. 安装
# React Router v6(目前主流版本)
npm install react-router-dom
# 它会作为 dependencies 装进 package.json
# react-router-dom = react-router 核心 + DOM 相关 API(浏览器用)本系列所有代码基于 React Router v6(目前主流)。v5 的 API 差异较大,看老教程时注意区分。
3. 基础路由
三个核心组件:BrowserRouter(包裹应用,启用路由)、Routes(路由容器)、Route(单条路由规则)。
import { BrowserRouter, Routes, Route } from "react-router-dom";
function App() {
return (
// BrowserRouter 包在最外层,启用路由功能
<BrowserRouter>
{/* Routes 是所有路由的容器 */}
<Routes>
{/* path 是 URL 路径,element 是要渲染的组件 */}
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/contact" element={<Contact />} />
</Routes>
</BrowserRouter>
);
}
function Home() { return <h1>首页</h1>; }
function About() { return <h1>关于我们</h1>; }
function Contact() { return <h1>联系我们</h1>; }
// 访问 / → Home
// 访问 /about → About
// 访问 /contact → Contactpath 是 URL 路径,element 是路径匹配时渲染的组件。访问不同 URL,React Router 自动切换显示对应组件——整个过程不刷新页面。
4. 用 Link 做导航
页面之间的跳转用 Link 组件,它会渲染成 <a> 标签,但点击时拦截默认跳转,改成 JS 切换路由:
import { Link, NavLink } from "react-router-dom";
function NavBar() {
return (
<nav>
{/* Link:渲染成 <a>,但不会真的刷新页面(SPA 核心) */}
<Link to="/">首页</Link>
<Link to="/about">关于</Link>
{/* NavLink:当前页对应的会自动加 active class */}
<NavLink to="/about" className="nav-link">
关于(高亮当前)
</NavLink>
</nav>
);
}
// ❌ 不要用 <a href="/about">:会整页刷新,SPA 体验全毁大忌:用原生 <a href="/about"> 会整页刷新,SPA 体验全毁。永远用 <Link to="...">。当前页对应的链接需要高亮时,用 NavLink——它会自动给激活的链接加 active class。
5. 动态路由参数
真实场景里,URL 经常带动态参数:用户详情 /users/42、文章 /posts/abc-123。React Router 用 :参数名 语法声明:
import { useParams } from "react-router-dom";
// 路由路径里的 :id 是"动态参数"
<Route path="/users/:id" element={<UserDetail />} />
function UserDetail() {
// useParams 读取 URL 里的参数
const { id } = useParams();
return <h1>用户 ID:{id}</h1>;
}
// 访问 /users/42 → 显示"用户 ID:42"
// 访问 /users/abc → 显示"用户 ID:abc"这是后端风格的路由,语义清晰、SEO 友好。useParams 是个 Hook,在任何子组件里都能调,拿到当前 URL 的参数。
6. 编程式导航
有时不能等用户点链接——比如登录成功后自动跳转、表单提交后跳到结果页。这时用 useNavigate Hook:
import { useNavigate } from "react-router-dom";
function LoginForm() {
const navigate = useNavigate();
const handleLogin = async () => {
// ... 登录逻辑
const ok = await login();
if (ok) {
navigate("/dashboard"); // 编程式跳转
// navigate(-1) → 后退一页(等价于浏览器后退)
// navigate(1) → 前进一页
// navigate("/p", { replace: true }) → 替换历史(不留下当前页)
}
};
return <button onClick={handleLogin}>登录</button>;
}navigate(path) 跳到指定路径,navigate(-1) 后退一页,navigate(1) 前进一页。配合 replace: true 可以"替换"历史(用户后退不会回到当前页)。
7. 嵌套路由
后台管理这类应用,有共享的布局(侧边栏、顶栏),只有内容区切换。React Router 用嵌套路由 + Outlet 优雅处理:
// 嵌套路由:Layout 共享侧边栏,内容区切换
function App() {
return (
<BrowserRouter>
<Routes>
{/* 父路由用 Outlet 标记子路由渲染位置 */}
<Route path="/dashboard" element={<DashboardLayout />}>
{/* 子路由 path 自动拼成 /dashboard/users */}
<Route index element={<Overview />} />
<Route path="users" element={<Users />} />
<Route path="settings" element={<Settings />} />
</Route>
</Routes>
</BrowserRouter>
);
}
function DashboardLayout() {
return (
<div className="layout">
<Sidebar />
<main>
{/* Outlet:子路由渲染在这里 */}
<Outlet />
</main>
</div>
);
}父路由的组件里放一个 <Outlet />,标记"子路由渲染在这里"。访问 /dashboard/users 时,DashboardLayout 和 Users 会同时渲染——布局共享,内容切换。index 路由表示父路径本身(/dashboard)显示的默认内容。
8. 404 页面
用户可能输入不存在的 URL,你需要一个"兜底"路由显示 404 页面:
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
{/* 兜底路由:放最后,匹配所有未命中的路径 */}
<Route path="*" element={<NotFound />} />
</Routes>
</BrowserRouter>
);
}
function NotFound() {
return (
<div>
<h1>404 - 页面不存在</h1>
<Link to="/">返回首页</Link>
</div>
);
}path="*" 是通配符,匹配所有未命中的路径。必须放在 Routes 的最后,否则它会"截胡"后面的路由。
9. 查询参数
除了 path 参数,URL 还有查询参数(?page=2&size=10)。用 useSearchParams 读取:
const [params, setParams] = useSearchParams()params.get("page")拿到"2"- 注意返回的是字符串,数字要自己
Number()转。
小结
React Router 让单页应用拥有多页体验。核心组件:BrowserRouter 包外层、Routes 装路由、Route 定义规则、Link 做导航。动态参数用 :id + useParams,编程式跳转用 useNavigate,共享布局用嵌套路由 + Outlet。下一篇看 React 组件"生命周期"——useEffect。
← 上一篇 受控组件与表单
下一篇 生命周期与 useEffect →