RouterProviderからのフレームワーク導入
このページの内容

RouterProviderからのフレームワーク導入

<RouterProvider>を使用していない場合は、代わりにコンポーネントルートからのフレームワーク導入を参照してください。

React Router Viteプラグインは、React Routerにフレームワーク機能を追加します。このガイドは、アプリにプラグインを導入するのに役立ちます。問題が発生した場合は、TwitterまたはDiscordでヘルプを求めてください。

機能

Viteプラグインは以下を追加します

  • ルートローダー、アクション、および自動データ再検証
  • タイプセーフなルートモジュール
  • 自動ルートコード分割
  • ナビゲーション間の自動スクロール復元
  • オプションの静的事前レンダリング
  • オプションのサーバーレンダリング

初期設定には最も多くの作業が必要です。ただし、完了すると、新しい機能を段階的に導入できます。

前提条件

Vite プラグインを使用するには、プロジェクトは以下の要件を満たす必要があります。

  • Node.js 20+ (Node をランタイムとして使用する場合)
  • Vite 5+

1. ルート定義をルートモジュールに移動する

React Router Vite プラグインは独自の RouterProvider をレンダリングするため、既存の RouterProvider をその中にレンダリングすることはできません。代わりに、すべてのルート定義を ルートモジュールAPI に一致するようにフォーマットする必要があります。

この手順には最も時間がかかりますが、React Router Vite プラグインを採用するかに関わらず、これを行うことにはいくつかの利点があります。

  • ルートモジュールは遅延ロードされ、アプリの初期バンドルサイズが削減されます。
  • ルート定義が統一され、アプリのアーキテクチャが簡素化されます。
  • ルートモジュールへの移行は段階的に行うことができ、一度に1つのルートを移行できます。

👉 ルート定義をルートモジュールに移動します。

ルートモジュール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 ファイルを作成します。

プロジェクトのルートに以下を追加します。この設定では、アプリディレクトリの場所や、今のところ SSR (サーバーサイドレンダリング) を使用しないなど、React Router にプロジェクトについて指示できます。

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

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

4. ルートエントリポイントを追加する

典型的な Vite アプリでは、index.html ファイルがバンドルのエントリポイントです。 React Router Vite プラグインは、エントリポイントを root.tsx ファイルに移動するため、静的 HTML の代わりに React を使用してアプリのシェルをレンダリングし、必要に応じてサーバーレンダリングにアップグレードできます。

👉 既存の index.htmlroot.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>
);
  • createRoot の代わりに hydrateRoot を使用します。
  • <App/> コンポーネントの代わりに <HydratedRouter> をレンダリングします。
  • 注: ルートを作成して <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

SSR および/またはプリレンダリングを有効にする

サーバーレンダリングと静的プリレンダリングを有効にする場合は、バンドラープラグインの ssr および prerender オプションを使用して行うことができます。SSR の場合、サーバービルドをサーバーにデプロイする必要もあります。詳細については、デプロイ をご覧ください。

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

export default {
  ssr: true,
  async prerender() {
    return ["/", "/about", "/contact"];
  },
} satisfies Config;
ドキュメントと例 CC 4.0