React Router v7 已经正式成为现代 React 应用的默认路由方案。相比过去的版本,v7 在数据加载、路由懒加载、错误边界、路由模块化等方面做了更统一、更现代化的设计。
本文带你快速掌握 基础用法 + 高级用法,适合从 v5/v6 升级或新项目使用
一、核心理念与变化概览
React Router v7 主要围绕三个关键词:
1. 路由是 UI 的一部分
-router 是组件
- 不再是配置式为主,组件式更自然
- Layout + Outlet 成为主流
2. 数据路由(Data Router)统一化
提供统一 API:
-
loader 数据加载
-
action 数据提交
-
lazy 懒加载路由资源
-
errorElement 错误边界
3. 组件即路由
v7 保留了 v6 的 createBrowserRouter、RouterProvider,并继续强化嵌套路由的概念
二、基础用法
1. 安装
npm install react-router-dom
2. 最简路由结构
import { createBrowserRouter, RouterProvider } from "react-router-dom";
const router = createBrowserRouter([
{
path: "/",
element: <HomePage />,
},
{
path: "/about",
element: <AboutPage />,
},
]);
export default function App() {
return <RouterProvider router={router} />;
}
3. Layout + Outlet(嵌套路由)
Layout 是 v7 强调的最佳实践:
import { Outlet, Link } from "react-router-dom";
function Layout() {
return (
<div>
<nav>
<Link to="/">首页</Link>
<Link to="/profile">个人中心</Link>
</nav>
<main>
<Outlet /> {/* 子路由在这里渲染 */}
</main>
</div>
);
}
const router = createBrowserRouter([
{
path: "/",
element: <Layout />,
children: [
{ index: true, element: <HomePage /> },
{ path: "profile", element: <ProfilePage /> },
],
},
]);
三、懒加载(async lazy)——强烈推荐写法
React Router v7 官方推荐使用 async lazy() 来进行路由级按需加载。
🔥 推荐写法:async lazy()
const router = createBrowserRouter([
{
path: "/",
async lazy() {
const Component = (await import("./pages/Layout")).default;
return { Component };
},
children: [
{
index: true,
async lazy() {
const Component = (await import("./pages/Home")).default;
return { Component };
},
},
{
path: "profile",
async lazy() {
const Component = (await import("./pages/Profile")).default;
return { Component };
},
},
],
},
]);
优势:
✔ 语法干净
✔ 和 Data Router 完整兼容
✔ 自动 Suspense
✔ 支持 SSR(未来版本)
✔ 大型项目结构清晰
四、跳转与参数读取
1. 跳转
const navigate = useNavigate();
navigate("/profile");
2. 获取路径参数
const { id } = useParams();
3. 获取查询参数
const [searchParams] = useSearchParams();
const keyword = searchParams.get("keyword");
五、跳转与参数读取(加强版)
这一部分很多人用得不全,这里讲 跳转方式、路径参数、查询参数、状态传参 4 大类。
📌 1. 跳转导航
(1)useNavigate:最常用跳转
import { useNavigate } from "react-router-dom";
const nav = useNavigate();
nav("/profile"); // 普通跳转
nav(-1); // 返回上一页
nav("/login", { replace: true }); // 不留历史记录
(2)链接跳转 Link
import { Link } from "react-router-dom";
<Link to="/about">关于我们</Link>
(3)按钮跳转 Navigate 组件
适合条件跳转:
{ isLogin ? <Dashboard /> : <Navigate to="/login" replace /> }
📌 2. 路径参数(URL Params)
例如访问:
/user/123
定义路由:
{
path: "user/:id",
element: <UserDetail />
}
读取参数:
import { useParams } from "react-router-dom";
const { id } = useParams(); // id === "123"
注意:
- params 一定是字符串类型
- 可用 Zod/Number() 做转换
📌 3. 查询参数(Search Params)
例如访问:
/list?page=2&keyword=test
读取:
import { useSearchParams } from "react-router-dom";
const [search] = useSearchParams();
const page = search.get("page");
const keyword = search.get("keyword");
修改:
const [search, setSearch] = useSearchParams();
setSearch({ page: 3 });
支持 append:
search.append("type", "A");
setSearch(search);
📌 4. 跳转时携带 state(非 URL)
类似 history.push 的 state:
nav("/detail", {
state: { from: "list", id: 123 }
});
读取:
import { useLocation } from "react-router-dom";
const { state } = useLocation();
// state.from === "list"
用法:
- 搜索列表 → 详情
- 跨页面临时数据
- 不污染 URL
- 仅会话内有效
六、Data Router:loader 与 action(高级)
📌 为什么需要 Data Router?
传统 SPA 数据加载流程:
渲染组件 → useEffect → fetch 数据 → setState →再渲染
但这有几个问题:
- 多层嵌套时 useEffect 非常乱
- SSR、预加载、切换页面时不能保证一致性
- 异步错误很难集中处理
- 首屏渲染过慢
- React 渲染后才请求数据,白屏时间更长
React Router v7 引入 Data Router 后,流程变成:
进入某个路由 → 执行 loader → 数据准备好 → 再渲染组件
好处:
- 页面渲染 之前 就拿到数据(首屏更快)
- 数据逻辑从 UI 分离
- 错误自动走路由 errorElement
- 多个 loader 并行执行
- 支持自动 revalidate(自动刷新)
- SSR & CSR 统一开发体验
📌 1. loader:加载页面数据
loader 是路由级数据加载函数:
{
path: "/detail/:id",
loader: async ({ params, request }) => {
const res = await fetch(`/api/detail/${params.id}`);
return res.json();
},
element: <DetailPage />
}
组件内读取:
import { useLoaderData } from "react-router-dom";
const data = useLoaderData();
2. action:表单提交逻辑
{
path: "/create",
action: async ({ request }) => {
const form = await request.formData();
return createItem(form);
},
element: <CreatePage />
}
配合 <Form>:
<Form method="post">
<input name="title" />
<button>提交</button>
</Form>
七、错误边界 errorElement
v7 支持路由级错误 UI:
{
path: "/",
element: <Layout />,
errorElement: <ErrorPage />,
}
读取异常:
const err = useRouteError();
八、handle:路由元信息(meta)
可用于:
{
path: "settings",
handle: { title: "系统设置", auth: true },
element: <SettingsPage />
}
读取所有匹配路由的 handle:
import { useMatches } from "react-router-dom";
const matches = useMatches();
九、模块化路由(大型项目最佳实践)
假设有三个模块:Dashboard、User、Project
1️⃣ Dashboard 模块
// routes/dashboard.routes.ts
export const dashboardRoutes = [
{
path: "dashboard",
async lazy() {
const Component = (await import("@/pages/Dashboard")).default;
return { Component };
},
handle: { title: "Dashboard" },
},
];
2️⃣ User 模块(带 loader/action)
// routes/user.routes.ts
export const userRoutes = [
{
path: "user",
async lazy() {
const Layout = (await import("@/pages/User/Layout")).default;
return { Component: Layout };
},
children: [
{
index: true,
async lazy() {
const Component = (await import("@/pages/User/List")).default;
return { Component };
},
handle: { title: "用户列表" },
},
],
},
];
3️⃣ Project 模块
// routes/project.routes.ts
export const projectRoutes = [
{
path: "project",
async lazy() {
const Layout = (await import("@/pages/Project/Layout")).default;
return { Component: Layout };
},
children: [
{
index: true,
async lazy() {
const Component = (await import("@/pages/Project/List")).default;
return { Component };
},
handle: { title: "项目列表" },
},
],
},
];
4️⃣ 主路由统一整合
// routes/index.ts
import { createBrowserRouter } from "react-router-dom";
import { dashboardRoutes } from "./dashboard.routes";
import { userRoutes } from "./user.routes";
import { projectRoutes } from "./project.routes";
const router = createBrowserRouter([
{
path: "/",
async lazy() {
const Layout = (await import("@/pages/Layout")).default;
return { Component: Layout };
},
children: [
...dashboardRoutes,
...userRoutes,
...projectRoutes,
],
},
{
path: "/login",
async lazy() {
const Component = (await import("@/pages/Login")).default;
return { Component };
},
},
{
path: "*",
async lazy() {
const Component = (await import("@/pages/NotFound")).default;
return { Component };
},
},
]);
export default router;
十、权限控制(结合 loader + handle)
{
path: "admin",
handle: { auth: true },
loader: async () => {
const login = await checkLogin();
if (!login) throw redirect("/login");
},
element: <Admin />
}
满足所有权限场景。
结语
React Router v7 是目前 React 生态最全面的 SPA/SSR 路由方案,它的优势包括:
- 统一的页面加载方式
- 按需加载(lazy)
- 模块化路由
- 真正意义的路由数据层
- 强大的错误边界和 handle
无论是小项目还是大型管理后台,它都足够可控且可扩展。