痛饮狂歌

React Router 三种模式深度对比:Framework Mode vs Data Mode vs Declarative Mode

2025-10-20
16 分钟阅读
入门教程

深入对比 React Router 的三种使用模式:Framework Mode(框架模式)、Data Mode(数据模式)、Declarative Mode(声明模式),帮助你选择最适合项目的路由方案。

#React #React Router #路由 #前端开发 #模式对比

React Router 三种模式深度对比:Framework Mode vs Data Mode vs Declarative Mode

React Router 作为 React 生态系统中最流行的路由解决方案,在最新版本中提供了三种不同的使用模式:Framework Mode(框架模式)、Data Mode(数据模式)、Declarative Mode(声明模式)。每种模式都有其独特的优势和适用场景。本文将深入对比这三种模式,帮助你做出明智的选择。

什么是 React Router 模式?

React Router 的模式代表了不同的抽象层次和控制权分配。从简单到复杂,从灵活到完整,三种模式为不同需求的开发者提供了合适的选择。

重要提示:所有模式都支持任何架构和部署目标(SPA、SSR、SSG 等)。选择模式的关键不在于你想要什么样的架构,而在于你希望 React Router 提供多少帮助。

1. 声明式模式(Declarative Mode)

概述

声明式模式是最基础、最直接的路由使用方式。它提供了核心的路由功能,让你能够快速上手 React Router。

核心特性

  • ✅ URL 到组件的映射
  • ✅ 应用内导航
  • ✅ 活动状态管理
  • ✅ 基本的 <Link>useNavigateuseLocation API
  • ✅ 简单易用,学习曲线平缓

代码示例

import { BrowserRouter, Routes, Route, Link, useNavigate } from 'react-router';

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 />} />
      </Routes>
    </BrowserRouter>
  );
}

function Home() {
  const navigate = useNavigate();
  
  return (
    <div>
      <h1>首页</h1>
      <button onClick={() => navigate('/about')}>
        前往关于页面
      </button>
    </div>
  );
}

适用场景

  • 从 React Router v6 迁移的项目
  • 简单的单页应用(SPA)
  • 不需要复杂数据加载的场景
  • 希望保持对项目架构完全控制的开发者

2. 数据模式(Data Mode)

概述

数据模式在声明式模式的基础上,增加了强大的数据加载和操作能力。它将路由配置移出 React 渲染,提供了更高效的数据管理方式。

核心特性

  • ✅ 所有声明式模式的功能
  • Loader - 路由级别的数据加载
  • Action - 表单提交和数据修改
  • useFetcher - 不阻塞导航的数据获取
  • ✅ 待定状态(Pending States)管理
  • ✅ 错误边界处理
  • ✅ 保持对打包和服务器抽象的控制

代码示例

import {
  createBrowserRouter,
  RouterProvider,
  useLoaderData,
  useFetcher,
} from 'react-router';

// 路由配置
const router = createBrowserRouter([
  {
    path: "/",
    element: <Layout />,
    children: [
      {
        path: "users/:userId",
        element: <UserProfile />,
        loader: async ({ params }) => {
          // 在路由渲染前加载数据
          const user = await fetchUser(params.userId);
          return { user };
        },
        action: async ({ request }) => {
          // 处理表单提交
          const formData = await request.formData();
          const result = await updateUser(formData);
          return result;
        }
      }
    ]
  }
]);

function UserProfile() {
  const { user } = useLoaderData();
  const fetcher = useFetcher();
  
  return (
    <div>
      <h1>{user.name}</h1>
      <fetcher.Form method="post">
        <input name="email" defaultValue={user.email} />
        <button type="submit">更新</button>
      </fetcher.Form>
    </div>
  );
}

function App() {
  return <RouterProvider router={router} />;
}

适用场景

  • 需要复杂数据加载的应用
  • 希望利用数据功能但保持架构控制
  • 需要处理表单提交和数据修改
  • 想要更好的加载状态管理

3. 框架模式(Framework Mode)

概述

框架模式是最高级别的抽象,通过 Vite 插件包装了数据模式,提供了完整的 React Router 开发体验。这是最强大但也最”固执己见”的模式。

核心特性

  • ✅ 所有数据模式的功能
  • 类型安全的 href - 编译时检查路由链接
  • 类型安全的路由模块 API - 完整的 TypeScript 支持
  • 智能代码分割 - 自动优化打包
  • SPA、SSR 和静态渲染 - 多种渲染策略
  • Vite 插件集成 - 开箱即用的开发体验
  • 文件系统路由 - 类似 Next.js 的路由约定

代码示例

// 使用 Vite 插件配置
// vite.config.js
import { reactRouter } from "@react-router/dev/vite";

export default {
  plugins: [
    reactRouter({
      // 自动扫描路由文件
      routes: async () => {
        return [
          {
            path: "/",
            file: "routes/home.tsx",
          },
          {
            path: "/users/:userId",
            file: "routes/users.$userId.tsx",
          }
        ];
      }
    })
  ]
};

// routes/users.$userId.tsx
import { json } from "react-router";
import type { Route } from "./+types/users.$userId";

// 类型安全的数据加载
export async function loader({ params }: Route.LoaderArgs) {
  const user = await fetchUser(params.userId);
  return json({ user });
}

// 类型安全的组件
export default function UserProfile({ loaderData }: Route.ComponentProps) {
  return <div>{loaderData.user.name}</div>;
}

适用场景

  • 全新的 React 项目
  • 需要完整的框架功能
  • 希望最大化开发效率
  • 需要 SSR 或静态生成
  • 团队可以接受框架的约定

API 可用性对比

这是官方提供的 API 在不同模式下的可用性表格,帮助你了解每种模式的功能范围:

组件 API

API框架模式数据模式声明式模式
<Link>
<NavLink>
<Form>
<Outlet>
<Navigate>
<Await>
<Meta>
<Scripts>
<ScrollRestoration>

Hooks API

API框架模式数据模式声明式模式
useNavigate
useLocation
useParams
useSearchParams
useLoaderData
useActionData
useNavigation
useFetcher
useFetchers
useSubmit
useRevalidator
useRouteError
useRouteLoaderData
useMatches
useAsyncError
useAsyncValue
useBlocker
usePrompt
useViewTransitionState

工具函数

API框架模式数据模式声明式模式
redirect
redirectDocument
json
defer
createCookie
createCookieSessionStorage
createMemorySessionStorage

三种模式对比

特性声明式模式数据模式框架模式
学习曲线⭐ 简单⭐⭐ 中等⭐⭐⭐ 较陡
配置复杂度
数据加载❌ 无✅ Loader✅ Loader
表单处理❌ 手动✅ Action✅ Action
类型安全基础基础✅ 完整
代码分割手动手动✅ 自动
SSR 支持需要配置✅ 开箱即用
控制权⭐⭐⭐ 完全控制⭐⭐ 部分控制⭐ 框架控制
迁移难度-中等困难
推荐场景简单 SPA数据密集型应用全栈应用

如何选择?

根据官方文档的建议,选择模式的关键在于你希望自己完成多少工作,以及你希望 React Router 提供多少帮助。

选择框架模式,如果你:

  • 🆕 太新而没有明确偏好 - 刚开始接触 React Router
  • 🔄 正在考虑其他框架 - 在 Next.js、Solid Start、SvelteKit、Astro、TanStack Start 等框架之间比较
  • 🚀 只想用 React 构建应用 - 不需要太多考虑架构细节
  • 不确定是否需要 SSR - 可能想要服务端渲染,也可能不需要
  • 📦 从 Remix 迁移 - React Router v7 是 Remix v2 的”下一版本”
  • 🔧 从 Next.js 迁移 - 想要类似的开发体验

推荐:直接使用框架模式开始你的项目。

选择数据模式,如果你:

  • 💾 想要数据功能但保持控制 - 需要数据加载和操作,但同时想控制打包、数据和服务器抽象
  • 已在 v6.4 使用数据路由 - 从 v6.4 开始使用数据路由器并且对当前方案满意

推荐:继续使用数据模式,享受数据功能的同时保持架构控制。

选择声明式模式,如果你:

  • 🎯 追求极简使用 - 希望尽可能简单地使用 React Router
  • 🔙 从 v6 迁移 - 对 <BrowserRouter> 的使用感到满意
  • 🔄 已有数据层 - 你的数据层要么跳过待定状态(如本地优先、后台数据复制/同步),要么有自己的抽象来处理它们
  • 📦 从 Create React App 迁移 - 虽然你可能想考虑框架模式

推荐:保持简单,使用声明式模式。

迁移路径

从声明式到数据模式

// 之前:声明式模式
<Route path="/user/:id" element={<UserProfile />} />

// 之后:数据模式
{
  path: "/user/:id",
  element: <UserProfile />,
  loader: async ({ params }) => {
    return fetchUser(params.id);
  }
}

从数据模式到框架模式

需要安装 Vite 插件并重构项目结构:

npm install @react-router/dev

然后配置 vite.config.js 并按照文件系统路由约定组织代码。

总结

React Router 的三种模式各有千秋:

  • 声明式模式适合追求简单和控制的开发者
  • 数据模式适合需要数据功能但不想被框架束缚的项目
  • 框架模式适合追求完整功能和开发效率的团队

选择哪种模式取决于你的项目需求、团队能力和长期规划。记住,没有一种模式是完美的,只有最适合你当前情况的模式。

如果你正在构建新项目,建议从声明式模式开始,随着需求增长逐步升级到数据模式或框架模式。如果你需要完整的全栈功能,直接选择框架模式可能是更好的选择。