模式选择
现在的 React Router 有三种可用模式:
- 声明式模式 : 就像使用 Jsx 代替
React.createElement(),声明模式是一种比较直观的路由模式 - 数据模式 : 通过将路由配置移出 React 渲染之外,数据通过
loader、action和useFetcher等 API - 框架模式 : 采用 Vite 插件包装的数据模式,以添加完整的 React Router 体验
一、声明式模式
声明式路由是 React Router 的 经典使用方式 , 通过 <Routes /> 、 <Route /> 等组件定义路由规则,结合 useNavigate() 、 useParams() 等 Hooks 实现导航与参数获取。
特点:
- 简单直接 : 路由配置与组件渲染深度集成,符合 React 组件化思维
- 基础功能 : 支持 URL 与组件匹配、客户端导航、活动状态(如
<NavLink />的激活状态) - 无额外抽象 : 不包含数据加载、 SSR 等高级功能,需手动整合其他库
import { BrowserRouter } from 'react-router';
ReactDom.createRoot(root).render(
<BrowserRouter>
<App />
</BrowserRouter>,
);
推荐理由:
- 小型项目 : 无需使用复杂的数据管理或 SSR
- 熟悉 React 的开发者 : 从 v6 迁移来的,习惯组件式路由定义
- 轻量级开发 : 使用 Vite/Webpack 等打包工具,状态管理由 Zustand/Redux 等库负责
- 想要尽可能简单地使用 React Router
- 来自 React Router 6 并且习惯使用
<BrowserRouter> - 有一个数据层,该数据层要么跳过挂起状态(如本地优先,后台数据复制/同步),要么有自己的抽象
- 来自
Create React App(已被官方放弃,github 源代码 create react app 最后一次推送是 9 个月前,最新的 npm 包也显示最后版本为 5.1.0 ,发布于 9 个月之前。而上上个版本已是 4 年前的产物了(官方称由于没有活跃的维护者)。目前 React 更推荐使用 Next.js 而不是。。。 React Router )
二、数据模式
数据式路由是 v7 的 关健创新 , 通过 createBrowserRouter() 创建“数据路由器”,将路由配置从组件渲染中抽离出去,引入 loader(数据懒加载) 、 action(表单提交) 等 API ,实现 数据与路由的深度绑定 。
特点是:
- 数据驱动 : 通过
loader在路由渲染前预加载数据(如用户信息、商品列表),useLoaderData获取数据 - 表单处理 : 通过
action处理表单提交(如登陆、新增数据),支持同步/一步操作 - 灵活控制 : 保留对打包工具、数据抽象的控制权,适合需要定制数据流程的项目
- SSR 友好 : 为 SSR 提供数据预加载支持 (需配合服务器端框架)
import {
createBrowserRouter ,
RouterProvider,
} from 'react-router';
let router = createBrowserRouter({
{
path: '/',
Component: Root,
loader: loadRootData,
}
});
ReactDom.createRoot(root).render(
<RouterProvider router={router} />
)
推荐使用缘由:
- 中大型项目 : 需要集中管理数据加载逻辑(如电商平台的商品详情页、用户中心)
- 复杂表达处理 : 需要处理表单提交、验证、数据持久化(如后台管理系统的表单)
- 需要 SSR 的项目 : 希望提升首屏加载速度( SEO 优化 ) ,但不想放弃对数据流程的控制
- 想用数据功能,但也希望控制捆绑、数据和服务器抽象
- 在 React Router 6.4 中启动了数据路由器并感到满意
三、框架模式
框架路由是 v7 的 终极模式 , 通过 @react-router/dev 插件封装数据式路由,提供 全栈开发体验。
特点是:
- 类型安全 : 支持 TypeScript 类型推断(如
params、loaderData的类型检查) - 只能代码分割 : 自动分割路由组件,减少初始
bundle大小 - 多渲染策略 : 支持 SPA 、 SSR 、 SSG
- 开箱即用 : 整合了路由、数据加载、 SSR 等功能,无需手动配置打包工具(如 Vite 插件 )
routes.ts
import { index , route } form '@react-router/dev/routes';
export default [
index('./home.tsx'),
route('products/:pid', './product.tsx'),
]
然后,可以访问路由模块 API ,其中包含类型安全参数、 loaderData 、 代码拆分 、 SPA/SSR/SSG 策略等
product.tsx
import { Route } from './types/product/tsx';
export async function loader({ params }: Route.LoaderArgs) {
let product = await getProduct(params.pid);
return { product };
}
export default function Product({ loaderData }: Route.ComponentProps) {
return <div>{loaderData.product.name}</div>;
}
推荐使用缘由:
- 全栈项目 : 需要同时处理前端路由和后端数据(如博客系统、 电商平台)
- SSR/SSG 需求 : 希望提升 SEO 或首屏加载速度(如内容型网站)
- 新手或迁移用户 : 对 React Router 不熟悉,或从 Next.js 、 remix 迁移而来,希望快速上手
- 追求效率的项目 : 不想花费时间配置打包工具与数据流程,希望专注于业务逻辑
- 正在考虑 Next.js 、 svelte 、 astrojs 、 tanstack start 等 (那和这个模式有什么关系呢又?我想用 Next.js 就直接用了,为啥非要用一个本成品)
- 只是想用 React 构建一些东西
四、 表格
| 纬度 | 声明式路由 | 数据式路由 | 框架式路由** |
|---|---|---|---|
| 项目规模 | 小型( < 10 个页面) | 中大型(10-50 个页面) | 大型( > 50 个页面) |
| 数据需求 | 简单(无需预加载/表单处理) | 复杂(需预加载/表单处理) | 复杂(需要集中管理数据流程) |
| SSR 需求 | - | 可选(需手动配置) | 由(开箱即用) |
| 控制权 | 高(完全手动配置) | 中(保留数据控制权) | 低(依赖框架抽象) |
| 学习成本 | 低(符合 React 思维) | 中(需要学习 loader/action ) | 高(需要理解框架抽象) |