React Router v6 全指南:路由懒加载、数据加载一步到位
·
今天我们把一个商城后台的路由需求拆解成 5 个场景,让你一次看懂 v6 的现代用法。
🎯 场景需求
- 登录页、仪表盘、商品管理、订单管理。
- 仪表盘下有多个子路由:概览页、报表、设置。
- 部分页面需要权限控制。
- 需要懒加载和“加载中”状态。
🧱 基础配置:createBrowserRouter
import {
createBrowserRouter,
RouterProvider,
} from 'react-router-dom';
const router = createBrowserRouter([
{
path: '/',
element: <Layout />,
errorElement: <ErrorPage />, // v6 的错误边界
children: [
{
index: true,
lazy: () => import('./pages/Dashboard'),
},
{
path: 'products',
loader: fetchProducts,
element: <Products />,
},
{
path: 'orders',
loader: fetchOrders,
element: <Orders />,
},
{
path: 'settings',
element: <Settings />,
},
],
},
{
path: '/login',
element: <Login />,
},
]);
function App() {
return <RouterProvider router={router} />;
}
RouterProvider是 v6.4+ 的新写法。lazy支持路由级别懒加载,自动处理 Suspense。loader用来在渲染前获取数据。
⚡ 路由懒加载与代码分割
lazy 组件形式:
// pages/Dashboard.jsx
export async function loader() {
const stats = await fetch('/api/stats').then((res) => res.json());
return { stats };
}
export default function Dashboard() {
const { stats } = useLoaderData();
return <div>欢迎回来,今日数据:{stats.users}</div>;
}
useLoaderData获取 loader 返回的数据。- 自动处理加载状态,需要配合
<React.Suspense fallback={...}>。
🔐 路由守卫:loader + redirect
export async function protectedLoader({ request }) {
const token = localStorage.getItem('token');
if (!token) {
throw redirect('/login');
}
const user = await fetchUser(token);
return { user };
}
const router = createBrowserRouter([
{
path: '/',
loader: protectedLoader,
element: <Layout />,
children: [/* ... */],
},
]);
- 如果没登录,
redirect会终止后续渲染。 - Loader 可以返回数据给子组件使用。
🔄 动态路由与 useParams
{
path: 'products/:id',
loader: async ({ params }) => {
return fetch(`/api/products/${params.id}`).then((res) => res.json());
},
element: <ProductDetail />,
}
function ProductDetail() {
const product = useLoaderData();
return <div>{product.name}</div>;
}
- 不需要再手动调用
useEffect请求,Loader 自动搞定。
🧩 Outlet 与嵌套路由
function Layout() {
return (
<div>
<Sidebar />
<main>
<Suspense fallback={<PageSkeleton />}>
<Outlet />
</Suspense>
</main>
</div>
);
}
Outlet是子路由的出口。- 在
Outlet外层加 Suspense 可以统一管理加载状态。
🧯 常见坑
| 坑 | 现象 | 解决 |
|---|---|---|
<Routes> 内嵌 <Route> 的旧写法报错 |
v6.4+ 改为 RouterProvider | 升级到 createBrowserRouter 写法 |
| loader 中请求失败 | 抛错误,自动跳到 errorElement | 在 errorElement 中用 useRouteError 拿错误 |
| 路由懒加载闪烁 | 缺 Suspense fallback | 外层加 <Suspense fallback={<Loading />}> |
| SSR 支持 | 需要搭配 Remix 或 Next.js App Router | 使用 StaticRouter + hydrateRoot |
⚖️ v5 vs v6 对比
| 特性 | v5 | v6 |
|---|---|---|
| 路由定义 | <Switch><Route/></Switch> |
createBrowserRouter 或 <Routes><Route/></Routes> |
| 精确匹配 | exact 属性 |
默认精确匹配 |
| 嵌套路由 | 需要手动传 props | Outlet 自动渲染子路由 |
| 动态加载 | 需要 Suspense 手动处理 | lazy 内置支持 |
| 数据加载 | useEffect 手写 |
loader/action 内置 |
🏁 小练习
- 把你老项目的 Router v5 改写成 v6,记录坑点。
- 给某个路由添加 errorElement,模拟接口报错。
- 写一个 Loader + Action 搭配的案例(例如表单提交)。
更多推荐


所有评论(0)