從 RouterProvider 採用框架
本頁面

從 RouterProvider 採用框架

如果您未使用 <RouterProvider>,請改為參閱從元件路由採用框架

React Router Vite 外掛程式為 React Router 新增了框架功能。本指南將協助您在應用程式中採用此外掛程式。如果您遇到任何問題,請透過 TwitterDiscord 尋求協助。

功能

Vite 外掛程式新增了

  • 路由載入器、動作和自動資料重新驗證
  • 型別安全的路由模組
  • 自動路由程式碼分割
  • 跨導航自動滾動恢復
  • 選用的靜態預先渲染
  • 選用的伺服器渲染

初始設定需要最多的工作。但是,一旦完成,您就可以逐步採用新功能。

先決條件

若要使用 Vite 外掛程式,您的專案需要

  • Node.js 20+ (如果使用 Node 作為您的執行階段)
  • Vite 5+

1. 將路由定義移至路由模組中

React Router Vite 外掛程式會渲染自己的 RouterProvider,因此您無法在其內渲染現有的 RouterProvider。相反地,您需要格式化所有路由定義以符合路由模組 API

此步驟將花費最長的時間,但是無論是否採用 React Router Vite 外掛程式,執行此步驟都有幾個好處

  • 路由模組將延遲載入,從而減少應用程式的初始套件大小
  • 路由定義將會統一,簡化應用程式的架構
  • 移至路由模組是漸進式的,您可以一次遷移一個路由

👉 將您的路由定義移至路由模組中

將路由定義的每個部分匯出為個別的具名匯出,遵循路由模組 API

export async function clientLoader() {
  return {
    title: "About",
  };
}

export default function About() {
  let data = useLoaderData();
  return <div>{data.title}</div>;
}

// clientAction, ErrorBoundary, etc.

👉 建立轉換函式

建立一個輔助函式,將路由模組定義轉換為資料路由器預期的格式

function convert(m: any) {
  let {
    clientLoader,
    clientAction,
    default: Component,
    ...rest
  } = m;
  return {
    ...rest,
    loader: clientLoader,
    action: clientAction,
    Component,
  };
}

👉 延遲載入並轉換您的路由模組

不要直接匯入路由模組,而是延遲載入並將其轉換為資料路由器預期的格式。

您的路由定義現在不僅符合路由模組 API,而且還能獲得程式碼分割路由的好處。

let router = createBrowserRouter([
  // ... other routes
  {
    path: "about",
-   loader: aboutLoader,
-   Component: About,
+   lazy: () => import("./routes/about").then(convert),
  },
  // ... other routes
]);

針對應用程式中的每個路由重複此程序。

2. 安裝 Vite 外掛程式

一旦您的所有路由定義都轉換為路由模組,您就可以採用 React Router 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()
  ],
});

3. 新增 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;

4. 新增 Root 進入點

在典型的 Vite 應用程式中,index.html 檔案是捆綁的進入點。React Router Vite 外掛程式將進入點移至 root.tsx 檔案,以便您可以使用 React 渲染應用程式的外殼,而不是靜態 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 />;
}

👉 將 RouterProvider 上方的所有內容移至 root.tsx

任何全域樣式、內容提供者等都應移至 root.tsx,以便它們可以在所有路由之間共用。

例如,如果您的 App.tsx 看起來像這樣

import "./index.css";

export default function App() {
  return (
    <OtherProviders>
      <AppLayout>
        <RouterProvider router={router} />
      </AppLayout>
    </OtherProviders>
  );
}

您會將 RouterProvider 上方的所有內容移至 root.tsx

+import "./index.css";

// ... other imports and Layout

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

5. 新增用戶端進入模組 (選用)

在典型的 Vite 應用程式中,index.html 檔案指向 src/main.tsx 作為用戶端進入點。React Router 改為使用名為 src/entry.client.tsx 的檔案。

如果 entry.client.tsx 不存在,React Router Vite 外掛程式將使用預設的隱藏檔案。

👉 將 src/entry.client.tsx 作為您的進入點

如果目前的 src/main.tsx 看起來像這樣

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

const router = createBrowserRouter([
  // ... route definitions
]);

ReactDOM.createRoot(
  document.getElementById("root")!
).render(
  <React.StrictMode>
    <RouterProvider router={router} />;
  </React.StrictMode>
);

您會將其重新命名為 entry.client.tsx 並將其變更為這樣

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

ReactDOM.hydrateRoot(
  document,
  <React.StrictMode>
    <HydratedRouter />
  </React.StrictMode>
);
  • 使用 hydrateRoot 而不是 createRoot
  • 渲染 <HydratedRouter> 而不是您的 <App/> 元件
  • 注意:我們不再建立路由並手動將其傳遞給 <RouterProvider />。我們將在下一步遷移我們的路由定義。

6. 遷移您的路由

React Router Vite 外掛程式使用 routes.ts 檔案來設定您的路由。格式將與您的資料路由器的定義非常相似。

👉 將定義移至 routes.ts 檔案

touch src/routes.ts src/catchall.tsx

將您的路由定義移至 routes.ts。請注意,結構描述並不完全相符,因此您會收到型別錯誤;我們將在下一步修正此問題。

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

-const router = createBrowserRouter([
+export default [
  {
    path: "/",
    lazy: () => import("./routes/layout").then(convert),
    children: [
      {
        index: true,
        lazy: () => import("./routes/home").then(convert),
      },
      {
        path: "about",
        lazy: () => import("./routes/about").then(convert),
      },
      {
        path: "todos",
        lazy: () => import("./routes/todos").then(convert),
        children: [
          {
            path: ":id",
            lazy: () =>
              import("./routes/todo").then(convert),
          },
        ],
      },
    ],
  },
-]);
+] satisfies RouteConfig;

👉 將 lazy 載入器取代為 file 載入器

export default [
  {
    path: "/",
-   lazy: () => import("./routes/layout").then(convert),
+   file: "./routes/layout.tsx",
    children: [
      {
        index: true,
-       lazy: () => import("./routes/home").then(convert),
+       file: "./routes/home.tsx",
      },
      {
        path: "about",
-       lazy: () => import("./routes/about").then(convert),
+       file: "./routes/about.tsx",
      },
      {
        path: "todos",
-       lazy: () => import("./routes/todos").then(convert),
+       file: "./routes/todos.tsx",
        children: [
          {
            path: ":id",
-           lazy: () => import("./routes/todo").then(convert),
+           file: "./routes/todo.tsx",
          },
        ],
      },
    ],
  },
] satisfies RouteConfig;

檢視我們關於設定路由的指南,以深入瞭解 routes.ts 檔案和輔助函式,以進一步簡化路由定義。

7. 啟動應用程式

此時,您應該已完全遷移到 React Router Vite 外掛程式。繼續更新您的 dev 指令碼並執行應用程式,以確保一切正常運作。

👉 新增 dev 指令碼並執行應用程式

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

現在請確保您可以在此時啟動您的應用程式,然後再繼續

npm run dev

您可能會想要將 .react-router/ 新增至您的 .gitignore 檔案,以避免追蹤儲存庫中不必要的檔案。

.react-router/

您可以查看型別安全,以瞭解如何完整設定和使用自動產生的型別安全,以用於參數、載入器資料等。

啟用 SSR 及/或預先渲染

如果您想要啟用伺服器渲染和靜態預先渲染,您可以使用捆綁器外掛程式中的 ssrprerender 選項來執行此操作。對於 SSR,您還需要將伺服器組建部署到伺服器。請參閱部署以取得更多資訊。

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

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