コンポーネントルートからのフレームワーク導入
このページの内容

コンポーネントルートからのフレームワーク導入

<RouterProvider>を使用している場合は、代わりにRouterProviderからのフレームワーク導入をご覧ください。

<Routes>を使用している場合は、ここは正しい場所です。

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

機能

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 ファイルを作成します。

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

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 ファイルに移動するため、静的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 />;
}

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>
);
  • createRoot の代わりに hydrateRoot を使用します。
  • <App/> コンポーネントの代わりに <HydratedRouter> をレンダリングします。
  • 注: <App/> コンポーネントのレンダリングを停止しました。後の手順で戻しますが、まずは新しいエントリポイントでアプリを起動できるようにします。

5. ファイルの整理

root.tsxentry.client.tsx の間で、いくつかの要素を整理したい場合があります。

一般的に

  • root.tsx には、コンテキストプロバイダー、レイアウト、スタイルなどのレンダリング関連のものが含まれます。
  • entry.client.tsx はできるだけ最小限にする必要があります。
  • 既存の <App/> コンポーネントをまだレンダリングしようとしないでください。後の手順で行います。

root.tsx ファイルは静的に生成され、アプリのエントリポイントとして提供されるため、そのモジュールのみがサーバーレンダリングと互換性がある必要があることに注意してください。 ここにほとんどの問題が発生します。

6. ルートを設定する

React Router Viteプラグインは、 routes.ts ファイルを使用してルートを設定します。 とりあえず、物事を進めるために単純なキャッチオールルートを追加します。

👉 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

8. アプリをレンダリングする

アプリのレンダリングに戻るには、以前に設定したすべてのURLに一致する「キャッチオール」ルートを更新して、既存の <Routes> がレンダリングされるようにします。

👉 アプリをレンダリングするようにキャッチオールルートを更新します。

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>;
}

パラメータ、ローダーデータなどの自動生成された型安全性を設定するには、型安全性を参照してください。

移行する最初のいくつかのルートは、さまざまな抽象化に以前とは少し異なる方法でアクセスする必要があるため、最も困難です(フックやコンテキストではなくローダーなど)。 しかし、最も難しい部分が処理されると、段階的な流れに入ります。

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