Suspense を使ったストリーミング

Suspense を使ったストリーミング

React Suspense を使用したストリーミングにより、重要ではないデータを遅延させ、UIレンダリングのブロックを解除することで、アプリの初期レンダリング速度を向上させることができます。

React Router は、ローダーとアクションから Promise を返すことで React Suspense をサポートしています。

1. ローダーから Promise を返す

React Router は、ルートコンポーネントをレンダリングする前にルートローダーを待機します。重要ではないデータのローダーのブロックを解除するには、ローダー内で await を行う代わりに Promise を返します。

import type { Route } from "./+types/my-route";

export async function loader({}: Route.LoaderArgs) {
  // note this is NOT awaited
  let nonCriticalData = new Promise((res) =>
    setTimeout(() => "non-critical", 5000)
  );

  let criticalData = await new Promise((res) =>
    setTimeout(() => "critical", 300)
  );

  return { nonCriticalData, criticalData };
}

2. フォールバックUIと解決済みUIをレンダリングする

Promise は `loaderData` で利用可能になり、`` は Promise を待機し、`` にフォールバックUIのレンダリングをトリガーします。

import * as React from "react";
import { Await } from "react-router";

// [previous code]

export default function MyComponent({
  loaderData,
}: Route.ComponentProps) {
  let { criticalData, nonCriticalData } = loaderData;

  return (
    <div>
      <h1>Streaming example</h1>
      <h2>Critical data value: {criticalData}</h2>

      <React.Suspense fallback={<div>Loading...</div>}>
        <Await resolve={nonCriticalData}>
          {(value) => <h3>Non critical value: {value}</h3>}
        </Await>
        <NonCriticalUI p={nonCriticalData} />
      </React.Suspense>
    </div>
  );
}

React 19 を使用する場合

React 19 を試している場合は、`Await` の代わりに `React.use` を使用できますが、新しいコンポーネントを作成し、Suspense フォールバックをトリガーするために Promise を渡す必要があります。

<React.Suspense fallback={<div>Loading...</div>}>
  <NonCriticalUI p={nonCriticalData} />
</React.Suspense>
function NonCriticalUI({ p }: { p: Promise<string> }) {
  let value = React.use(p);
  return <h3>Non critical value {value}</h3>;
}
ドキュメントと例 CC 4.0