スペシャルファイル

React Routerは、プロジェクト内でいくつかの特別なファイルを探します。これらのファイルのすべてが必須というわけではありません。

react-router.config.ts

このファイルはオプションです

この設定ファイルは、サーバーサイドレンダリングを使用しているかどうか、特定のディレクトリがどこに配置されているかなど、アプリの特定の側面を設定するために使用されます。

react-router.config.ts
import type { Config } from "@react-router/dev/config";
 
export default {
  // 設定オプション...
} satisfies Config;

詳細は、設定APIを参照してください。

root.tsx

このファイルは必須です

"ルート"ルート(app/root.tsx)は、React Routerアプリケーションで唯一_必須_のルートです。これは、routes/ディレクトリ内のすべてのルートの親であり、ルート<html>ドキュメントのレンダリングを担当するためです。

ルートルートはドキュメントを管理するため、React Routerが提供するいくつかの「ドキュメントレベル」コンポーネントをレンダリングするのに適した場所です。これらのコンポーネントは、ルートルート内で一度使用され、ページが正しくレンダリングされるためにReact Routerが認識または構築したすべてのものを含みます。

app/root.tsx
import type { LinksFunction } from "react-router";
import {
  Links,
  Meta,
  Outlet,
  Scripts,
  ScrollRestoration,
} from "react-router";
 
import "./global-styles.css";
 
export default function App() {
  return (
    <html lang="en">
      <head>
        <meta charSet="utf-8" />
        <meta
          name="viewport"
          content="width=device-width, initial-scale=1"
        />
 
        {/* すべてのルートのすべての`meta`エクスポートはここでレンダリングされます */}
        <Meta />
 
        {/* すべてのルートのすべての`link`エクスポートはここでレンダリングされます */}
        <Links />
      </head>
      <body>
        {/* 子ルートはここでレンダリングされます */}
        <Outlet />
 
        {/* クライアント側のトランジションのスクロール位置を管理します */}
        {/* スクリプトにnonceベースのコンテンツセキュリティポリシーを使用する場合は、`nonce`プロップを指定する必要があります。それ以外の場合は、ここに示すようにnonceプロップを省略してください。 */}
        <ScrollRestoration />
 
        {/* スクリプトタグはここにあります */}
        {/* スクリプトにnonceベースのコンテンツセキュリティポリシーを使用する場合は、`nonce`プロップを指定する必要があります。それ以外の場合は、ここに示すようにnonceプロップを省略してください。 */}
        <Scripts />
      </body>
    </html>
  );
}

Layoutエクスポート

ルートルートは、すべてのルートモジュールエクスポートをサポートしています。

ルートルートは、追加のオプションのLayoutエクスポートもサポートしています。Layoutコンポーネントは2つの目的を果たします。

  1. ルートコンポーネント、HydrateFallbackErrorBoundary全体でドキュメントの「アプリシェル」を複製するのを避ける
  2. Reactが<Links>コンポーネントから<link rel="stylesheet">タグを削除して再追加する場合に、Reactがアプリシェルの要素を再マウントするのを防ぎ、FOUCが発生するのを防ぎます。
app/root.tsx
export function Layout({ children }) {
  return (
    <html lang="en">
      <head>
        <meta charSet="utf-8" />
        <meta
          name="viewport"
          content="width=device-width, initial-scale=1"
        />
        <Meta />
        <Links />
      </head>
      <body>
        {/* childrenはルートコンポーネント、ErrorBoundary、またはHydrateFallbackになります */}
        {children}
        <Scripts />
        <ScrollRestoration />
      </body>
    </html>
  );
}
 
export default function App() {
  return <Outlet />;
}
 
export function ErrorBoundary() {}

LayoutコンポーネントでのuseLoaderDataに関する注意事項

useLoaderDataErrorBoundaryコンポーネントで使用することは許可されていません。これは、ハッピーパスルートレンダリングを目的としており、その型定義には、loaderが正常に実行され、何かを返したという組み込みの仮定があるためです。loaderがスローして境界をトリガーした可能性があるため、ErrorBoundaryではこの仮定は成り立ちません!ErrorBoundaryでローダーデータにアクセスするには、useRouteLoaderDataを使用できます。これは、ローダーデータがundefinedである可能性を考慮します。

Layoutコンポーネントは成功とエラーの両方のフローで使用されるため、同じ制限が適用されます。成功したリクエストだったかどうかによってLayoutのロジックを分岐させる必要がある場合は、useRouteLoaderData("root")useRouteError()を使用できます。

<Layout>コンポーネントはErrorBoundaryのレンダリングに使用されるため、ErrorBoundaryをレンダリングエラーに遭遇することなくレンダリングできることを確認するために、_非常に防御的に_する必要があります。Layoutが境界をレンダリングしようとして別のエラーをスローした場合、それは使用できなくなり、UIは非常に最小限の組み込みデフォルトErrorBoundaryにフォールバックします。

app/root.tsx
export function Layout({
  children,
}: {
  children: React.ReactNode;
}) {
  const data = useRouteLoaderData("root");
  const error = useRouteError();
 
  return (
    <html lang="en">
      <head>
        <meta charSet="utf-8" />
        <meta
          name="viewport"
          content="width=device-width, initial-scale=1"
        />
        <Meta />
        <Links />
        <style
          dangerouslySetInnerHTML={{
            __html: `
              :root {
                --themeVar: ${
                  data?.themeVar || defaultThemeVar
                }
              }
            `,
          }}
        />
      </head>
      <body>
        {data ? (
          <Analytics token={data.analyticsToken} />
        ) : null}
        {children}
        <ScrollRestoration />
        <Scripts />
      </body>
    </html>
  );
}

routes.ts

このファイルは必須です

routes.tsファイルは、どのURLパターンがどのルートモジュールに一致するかを設定するために使用されます。

app/routes.ts
import {
  type RouteConfig,
  route,
} from "@react-router/dev/routes";
 
export default [
  route("some/path", "./some/file.tsx"),
  // パターン ^           ^ モジュールファイル
] satisfies RouteConfig;

詳細は、ルーティングガイドを参照してください。

entry.client.tsx

このファイルはオプションです

デフォルトでは、React Routerはクライアントでのアプリのハイドレーションを処理します。次のコマンドでデフォルトのエントリクライアントファイルを公開できます。

react-router reveal

このファイルはブラウザのエントリポイントであり、サーバーエントリモジュールでサーバーによって生成されたマークアップをハイドレートする役割を果たしますが、ここで他のクライアントサイドコードを初期化することもできます。

app/entry.client.tsx
import { startTransition, StrictMode } from "react";
import { hydrateRoot } from "react-dom/client";
import { HydratedRouter } from "react-router/dom";
 
startTransition(() => {
  hydrateRoot(
    document,
    <StrictMode>
      <HydratedRouter />
    </StrictMode>
  );
});

これはブラウザで最初に実行されるコードです。クライアント側のライブラリを初期化したり、クライアント専用のプロバイダーを追加したりできます。

entry.server.tsx

このファイルはオプションです

デフォルトでは、React RouterはHTTPレスポンスの生成を処理します。次のコマンドでデフォルトのエントリサーバーファイルを公開できます。

react-router reveal

このモジュールのdefaultエクスポートは、HTTPステータス、ヘッダー、HTMLを含むレスポンスを作成できる関数であり、マークアップの生成とクライアントへの送信方法を完全に制御できます。

このモジュールは、現在のリクエストのcontexturlを使用して<ServerRouter>要素を使用して現在のページのマークアップをレンダリングする必要があります。このマークアップは(オプションで)、クライアントエントリモジュールを使用してJavaScriptがブラウザにロードされた後に再ハイドレートされます。

handleDataRequest

データリクエストのレスポンスを変更できるオプションのhandleDataRequest関数をエクスポートできます。これらは、HTMLをレンダリングするのではなく、クライアント側のハイドレーションが発生した後にローダーとアクションデータをブラウザに返すリクエストです。

export function handleDataRequest(
  response: Response,
  {
    request,
    params,
    context,
  }: LoaderFunctionArgs | ActionFunctionArgs
) {
  response.headers.set("X-Custom-Header", "value");
  return response;
}

handleError

デフォルトでは、React Routerは発生したサーバーサイドエラーをコンソールに出力します。ロギングをより詳細に制御したい場合、またはこれらのエラーを外部サービスにも報告したい場合は、オプションのhandleError関数をエクスポートできます。これにより、制御が可能になり(組み込みのエラーロギングは無効になります)。

export function handleError(
  error: unknown,
  {
    request,
    params,
    context,
  }: LoaderFunctionArgs | ActionFunctionArgs
) {
  if (!request.signal.aborted) {
    sendErrorToErrorReportingService(error);
    console.error(formatErrorForJsonLogging(error));
  }
}

リクエストが中断された場合にロギングを避けるのが一般的です。React Routerのキャンセルと競合状態の処理により、多くのリクエストが中断される可能性があるためです。

ストリーミングレンダリングエラー

renderToPipeableStreamまたはrenderToReadableStreamを使用してHTMLレスポンスをストリーミングしている場合、独自のhandleError実装は、最初のシェルレンダリング中に発生したエラーのみを処理します。後続のストリーミングレンダリング中にレンダリングエラーが発生した場合、React Routerサーバーはすでにレスポンスを送信しているため、これらのエラーを手動で処理する必要があります。

renderToPipeableStreamの場合、onErrorコールバック関数でこれらのエラーを処理できます。エラーがシェルレンダリングエラー(無視できる)か非同期エラーかを判断するために、onShellReadyでブール値を切り替える必要があります。

例については、ノードのデフォルトのentry.server.tsxを参照してください。

スローされたレスポンス

これは、loader/action関数からスローされたResponseインスタンスを処理しません。このハンドラの目的は、予期しないスローされたエラーを引き起こすコードのバグを見つけることです。シナリオを検出してloader/actionで401/404などのResponseをスローしている場合は、コードによって処理される予期されたフローです。これらのエラーをログに記録したり、外部サービスに送信したりする必要がある場合も、レスポンスをスローした時点で実行する必要があります。