使用 Suspense 進行串流

使用 Suspense 進行串流

使用 React Suspense 進行串流讓應用程式能透過延遲非關鍵資料和解除封鎖 UI 渲染,來加速初始渲染。

React Router 透過從 loaders 和 actions 返回 promise 來支援 React Suspense。

1. 從 loader 返回 promise

React Router 在渲染路由元件之前會等待路由 loaders。為了解除封鎖非關鍵資料的 loader,請返回 promise,而不是在 loader 中等待它。

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

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

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

  return { nonCriticalData, criticalData };
}

2. 渲染 fallback 和已解析的 UI

promise 將在 loaderData 上可用,<Await> 將等待 promise 並觸發 <Suspense> 渲染 fallback 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>
      </React.Suspense>
    </div>
  );
}

使用 React 19

如果您正在試用 React 19,您可以使用 React.use 而不是 Await,但您需要建立一個新元件並將 promise 傳遞下去以觸發 suspense fallback。

<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