使用 Suspense 进行流式传输
本页内容

使用 Suspense 进行流式传输



使用 React Suspense 进行流式传输,允许应用程序通过延迟非关键数据和解除 UI 渲染阻塞来加速初始渲染。

React Router 通过从加载器和操作中返回 promise 来支持 React Suspense。

1. 从加载器返回一个 promise

React Router 在渲染路由组件之前会等待路由加载器。为了解除非关键数据的加载器阻塞,请返回 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(() => res("non-critical"), 5000),
  );

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

  return { nonCriticalData, criticalData };
}

注意,你不能返回单个 promise,它必须是一个带有键的对象。

2. 渲染后备和已解析的 UI

该 promise 将在 `loaderData` 上可用,`<Await>` 将等待该 promise 并触发 `<Suspense>` 来渲染后备 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 后备。

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

超时

默认情况下,加载器和操作会在 4950 毫秒后拒绝任何未完成的 promise。你可以通过从 `entry.server.tsx` 导出 `streamTimeout` 数值来控制此行为。

// Reject all pending promises from handler functions after 10 seconds
export const streamTimeout = 10_000;
文档和示例 CC 4.0
编辑