从组件路由采用框架
本页目录

从组件路由采用框架

如果你正在使用 <RouterProvider>,请查看 从 RouterProvider 采用框架

如果你正在使用 <Routes>,那么这里是正确的地方。

React Router Vite 插件为 React Router 添加了框架特性。本指南将帮助你在你的应用中采用该插件。如果你遇到任何问题,请在 TwitterDiscord 上寻求帮助。

特性

Vite 插件添加了

  • 路由加载器、操作和自动数据重新验证
  • 类型安全的路由模块
  • 自动路由代码拆分
  • 跨导航自动滚动恢复
  • 可选的静态预渲染
  • 可选的服务端渲染

初始设置需要最多的工作。但是,一旦完成,你可以逐步采用新特性,一次一个路由。

先决条件

要使用 Vite 插件,你的项目需要

  • Node.js 20+(如果使用 Node 作为你的运行时)
  • Vite 5+

1. 安装 Vite 插件

👉 安装 React Router Vite 插件

npm install -D @react-router/dev

👉 安装运行时适配器

我们将假设你正在使用 Node 作为你的运行时。

npm install @react-router/node

👉 将 React 插件替换为 React Router。

-import react from '@vitejs/plugin-react'
+import { reactRouter } from "@react-router/dev/vite";
import { defineConfig } from "vite";


export default defineConfig({
  plugins: [
-    react()
+    reactRouter()
  ],
});

2. 添加 React Router 配置

👉 创建一个 react-router.config.ts 文件

将以下内容添加到你的项目根目录。在此配置中,你可以告诉 React Router 关于你的项目的信息,例如在哪里找到应用目录,以及暂时不使用 SSR(服务端渲染)。

touch react-router.config.ts
import type { Config } from "@react-router/dev/config";

export default {
  appDirectory: "src",
  ssr: false,
} satisfies Config;

3. 添加根入口点

在一个典型的 Vite 应用中,index.html 文件是打包的入口点。React Router Vite 插件将入口点移动到一个 root.tsx 文件,这样你可以使用 React 来渲染你的应用的 shell,而不是静态 HTML,并且最终可以升级到服务端渲染(如果你愿意)。

👉 将你现有的 index.html 移动到 root.tsx

例如,如果你的当前 index.html 看起来像这样

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta
      name="viewport"
      content="width=device-width, initial-scale=1.0"
    />
    <title>My App</title>
  </head>
  <body>
    <div id="root"></div>
    <script type="module" src="/src/main.tsx"></script>
  </body>
</html>

你将把该标记移动到 src/root.tsx 并删除 index.html

touch src/root.tsx
import {
  Links,
  Meta,
  Outlet,
  Scripts,
  ScrollRestoration,
} from "react-router";

export function Layout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <head>
        <meta charSet="UTF-8" />
        <meta
          name="viewport"
          content="width=device-width, initial-scale=1.0"
        />
        <title>My App</title>
        <Meta />
        <Links />
      </head>
      <body>
        {children}
        <ScrollRestoration />
        <Scripts />
      </body>
    </html>
  );
}

export default function Root() {
  return <Outlet />;
}

4. 添加客户端入口模块

在典型的 Vite 应用中,index.html 文件指向 src/main.tsx 作为客户端入口点。React Router 使用一个名为 src/entry.client.tsx 的文件来代替。

👉 将 src/entry.client.tsx 作为你的入口点

如果你的当前 src/main.tsx 看起来像这样

import React from "react";
import ReactDOM from "react-dom/client";
import { BrowserRouter } from "react-router";
import "./index.css";
import App from "./App";

ReactDOM.createRoot(
  document.getElementById("root")!
).render(
  <React.StrictMode>
    <BrowserRouter>
      <App />
    </BrowserRouter>
  </React.StrictMode>
);

你将把它重命名为 entry.client.tsx 并更改为这样

import React from "react";
import ReactDOM from "react-dom/client";
import { HydratedRouter } from "react-router/dom";
import "./index.css";

ReactDOM.hydrateRoot(
  document,
  <React.StrictMode>
    <HydratedRouter />
  </React.StrictMode>
);
  • 使用 hydrateRoot 而不是 createRoot
  • 渲染 <HydratedRouter> 而不是你的 <App/> 组件
  • 注意:我们停止了渲染 <App/> 组件。我们将在稍后的步骤中把它带回来,但首先我们希望应用能够使用新的入口点启动。

5. 调整文件结构

root.tsxentry.client.tsx 之间,你可能需要调整它们之间的一些内容。

一般来说

  • root.tsx 包含任何渲染相关的东西,例如上下文提供器、布局、样式等。
  • entry.client.tsx 应该尽可能简洁
  • 记住不要尝试渲染你现有的 <App/> 组件,我们将在稍后的步骤中执行此操作

请注意,你的 root.tsx 文件将被静态生成并作为你的应用的入口点提供,因此只有该模块需要与服务端渲染兼容。这是你遇到的大部分麻烦的来源。

6. 设置你的路由

React Router Vite 插件使用 routes.ts 文件来配置你的路由。现在我们将添加一个简单的 catchall 路由来启动。

👉 设置一个 catchall.tsx 路由

touch src/routes.ts src/catchall.tsx
import {
  type RouteConfig,
  route,
} from "@react-router/dev/routes";

export default [
  // * matches all URLs, the ? makes it optional so it will match / as well
  route("*?", "catchall.tsx"),
] satisfies RouteConfig;

👉 渲染一个占位符路由

最终我们将用我们原始的 App 组件替换它,但现在我们只渲染一些简单的东西来确保我们可以启动应用。

export default function Component() {
  return <div>Hello, world!</div>;
}

查看我们的路由配置指南,了解更多关于 routes.ts 文件的信息。

7. 启动应用

此时你应该能够启动应用并看到根布局。

👉 添加 dev 脚本并运行应用

"scripts": {
  "dev": "react-router dev"
}

现在确保你可以在此时启动你的应用,然后再继续下一步

npm run dev

你可能需要将 .react-router/ 添加到你的 .gitignore 文件中,以避免在你的仓库中跟踪不必要的文件。

.react-router/

你可以查看 类型安全,了解如何完全设置和使用为参数、加载器数据等自动生成的类型安全。

8. 渲染你的应用

为了回到渲染你的应用,我们将更新我们之前设置的“catchall”路由,它匹配所有 URL,以便你现有的 <Routes> 有机会渲染。

👉 更新 catchall 路由以渲染你的应用

import App from "./App";

export default function Component() {
  return <App />;
}

你的应用应该回到屏幕上并像往常一样工作!

9. 将路由迁移到路由模块

你现在可以逐步将你的路由迁移到路由模块。

给定一个像这样的现有路由

// ...
import About from "./containers/About";

export default function App() {
  return (
    <Routes>
      <Route path="/about" element={<About />} />
    </Routes>
  );
}

👉 将路由定义添加到 routes.ts

import {
  type RouteConfig,
  route,
} from "@react-router/dev/routes";

export default [
  route("/about", "./pages/about.tsx"),
  route("*?", "catchall.tsx"),
] satisfies RouteConfig;

👉 添加路由模块

编辑路由模块以使用 路由模块 API

export async function clientLoader() {
  // you can now fetch data here
  return {
    title: "About page",
  };
}

export default function Component({ loaderData }) {
  return <h1>{loaderData.title}</h1>;
}

请参阅 类型安全,以设置参数、加载器数据等的自动生成类型安全。

你迁移的前几个路由是最难的,因为你经常需要以与以前稍有不同的方式访问各种抽象(例如在加载器中而不是从 Hook 或上下文中)。但是一旦处理完最棘手的部分,你就会进入一个渐进的节奏。

启用 SSR 和/或预渲染

如果你想启用服务端渲染和静态预渲染,你可以使用 bundler 插件中的 ssrprerender 选项来完成。对于 SSR,你还需要将服务器构建部署到服务器。请参阅 部署 以获取更多信息。

import type { Config } from "@react-router/dev/config";

export default {
  ssr: true,
  async prerender() {
    return ["/", "/about", "/contact"];
  },
} satisfies Config;
文档和示例 CC 4.0