Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 53 additions & 54 deletions src/content/reference/react-dom/server/resume.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ title: resume

<Intro>

`resume` streams a pre-rendered React tree to a [Readable Web Stream.](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream)
`resume` 将预渲染的 React 树流式传输到 [Web 可读流](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream)

```js
const stream = await resume(reactNode, postponedState, options?)
Expand All @@ -16,17 +16,17 @@ const stream = await resume(reactNode, postponedState, options?)

<Note>

This API depends on [Web Streams.](https://developer.mozilla.org/en-US/docs/Web/API/Streams_API) For Node.js, use [`resumeToNodeStream`](/reference/react-dom/server/renderToPipeableStream) instead.
API 依赖于 [Web ](https://developer.mozilla.org/en-US/docs/Web/API/Streams_API)。对于 Node.js,请改用 [`resumeToNodeStream`](/reference/react-dom/server/renderToPipeableStream)

</Note>

---

## Reference {/*reference*/}
## 参考 {/*reference*/}

### `resume(node, postponedState, options?)` {/*resume*/}

Call `resume` to resume rendering a pre-rendered React tree as HTML into a [Readable Web Stream.](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream)
调用 `resume`,将预渲染的 React 树继续渲染为 HTML,并写入 [Web 可读流](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream)

```js
import { resume } from 'react-dom/server';
Expand All @@ -39,39 +39,39 @@ async function handler(request, writable) {
}
```

[See more examples below.](#usage)
[请参阅下面的更多示例](#usage)

#### Parameters {/*parameters*/}
#### 参数 {/*parameters*/}

* `reactNode`: The React node you called `prerender` with. For example, a JSX element like `<App />`. It is expected to represent the entire document, so the `App` component should render the `<html>` tag.
* `postponedState`: The opaque `postpone` object returned from a [prerender API](/reference/react-dom/static/index), loaded from wherever you stored it (e.g. redis, a file, or S3).
* **optional** `options`: An object with streaming options.
* **optional** `nonce`: A [`nonce`](http://developer.mozilla.org/en-US/docs/Web/HTML/Element/script#nonce) string to allow scripts for [`script-src` Content-Security-Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/script-src).
* **optional** `signal`: An [abort signal](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) that lets you [abort server rendering](#aborting-server-rendering) and render the rest on the client.
* **optional** `onError`: A callback that fires whenever there is a server error, whether [recoverable](/reference/react-dom/server/renderToReadableStream#recovering-from-errors-outside-the-shell) or [not.](/reference/react-dom/server/renderToReadableStream#recovering-from-errors-inside-the-shell) By default, this only calls `console.error`. If you override it to [log crash reports,](/reference/react-dom/server/renderToReadableStream#logging-crashes-on-the-server) make sure that you still call `console.error`.
* `reactNode`:调用 `prerender` 时传入的 React 节点。例如,像 `<App />` 这样的 JSX 元素。它应表示整个文档,因此 `App` 组件应渲染 `<html>` 标签。
* `postponedState`:从 [prerender API](/reference/react-dom/static/index) 返回的不透明 `postpone` 对象,从你存储它的位置加载(例如 Redis、文件或 S3)。
* **可选** `options`:包含流式传输选项的对象。
* **可选** `nonce`:一个 [`nonce`](http://developer.mozilla.org/en-US/docs/Web/HTML/Element/script#nonce) 字符串,用于允许 [`script-src` 内容安全策略](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/script-src) 中的脚本。
* **可选** `signal`:一个 [中止信号](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal),允许你 [中止服务端渲染](#aborting-server-rendering),并在客户端渲染剩余内容。
* **可选** `onError`:每当发生服务端错误时触发的回调函数,无论错误是 [可恢复](/reference/react-dom/server/renderToReadableStream#recovering-from-errors-outside-the-shell) 还是 [不可恢复](/reference/react-dom/server/renderToReadableStream#recovering-from-errors-inside-the-shell)。默认情况下,它只调用 `console.error`。如果你重写它来 [记录崩溃报告](/reference/react-dom/server/renderToReadableStream#logging-crashes-on-the-server),请确保仍然调用 `console.error`


#### Returns {/*returns*/}
#### 返回值 {/*returns*/}

`resume` returns a Promise:
`resume` 返回一个 Promise

- If `resume` successfully produced a [shell](/reference/react-dom/server/renderToReadableStream#specifying-what-goes-into-the-shell), that Promise will resolve to a [Readable Web Stream.](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream) that can be piped to a [Writable Web Stream.](https://developer.mozilla.org/en-US/docs/Web/API/WritableStream).
- If an error happens in the shell, the Promise will reject with that error.
- 如果 `resume` 成功生成了 [shell](/reference/react-dom/server/renderToReadableStream#specifying-what-goes-into-the-shell),该 Promise 将解析为一个 [Web 可读流](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream),可以将其通过管道传输到 [Web 可写流](https://developer.mozilla.org/en-US/docs/Web/API/WritableStream)
- 如果 shell 中发生错误,Promise 将因该错误而被拒绝。

The returned stream has an additional property:
返回的流还有一个额外属性:

* `allReady`: A Promise that resolves when all rendering is complete. You can `await stream.allReady` before returning a response [for crawlers and static generation.](/reference/react-dom/server/renderToReadableStream#waiting-for-all-content-to-load-for-crawlers-and-static-generation) If you do that, you won't get any progressive loading. The stream will contain the final HTML.
* `allReady`:一个在所有渲染完成后解析的 Promise。你可以在返回响应之前 `await stream.allReady`,以供 [爬虫和静态生成](/reference/react-dom/server/renderToReadableStream#waiting-for-all-content-to-load-for-crawlers-and-static-generation) 使用。这样做不会有任何渐进式加载,流中将包含最终的 HTML

#### Caveats {/*caveats*/}
#### 注意事项 {/*caveats*/}

- `resume` does not accept options for `bootstrapScripts`, `bootstrapScriptContent`, or `bootstrapModules`. Instead, you need to pass these options to the `prerender` call that generates the `postponedState`. You can also inject bootstrap content into the writable stream manually.
- `resume` does not accept `identifierPrefix` since the prefix needs to be the same in both `prerender` and `resume`.
- Since `nonce` cannot be provided to prerender, you should only provide `nonce` to `resume` if you're not providing scripts to prerender.
- `resume` re-renders from the root until it finds a component that was not fully pre-rendered. Only fully prerendered Components (the Component and its children finished prerendering) are skipped entirely.
- `resume` 不接受 `bootstrapScripts``bootstrapScriptContent` `bootstrapModules` 选项。相反,你需要将这些选项传递给生成 `postponedState` 的 `prerender` 调用。你也可以手动将引导内容注入可写流。
- `resume` 不接受 `identifierPrefix`,因为该前缀在 `prerender` `resume` 中必须保持一致。
- 由于不能向 `prerender` 提供 `nonce`,只有在没有向 `prerender` 提供脚本时,才应向 `resume` 提供 `nonce`。
- `resume` 会从根节点重新渲染,直到找到一个未完全预渲染的组件。只有完全预渲染的组件(组件及其子组件都已完成预渲染)才会被完全跳过。

## Usage {/*usage*/}
## 用法 {/*usage*/}

### Resuming a prerender {/*resuming-a-prerender*/}
### 恢复预渲染 {/*resuming-a-prerender*/}

<Sandpack>

Expand All @@ -80,11 +80,11 @@ The returned stream has an additional property:

```html public/index.html
<!DOCTYPE html>
<html lang="en">
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<title>文档</title>
</head>
<body>
<iframe id="container"></iframe>
Expand All @@ -105,7 +105,7 @@ import { resume } from "react-dom/server";
import { hydrateRoot } from "react-dom/client";

function Header() {
return <header>Me and my descendants can be prerendered</header>;
return <header>我和我的后代都可以被预渲染</header>;
}

const { promise: cookies, resolve: resolveCookies } = Promise.withResolvers();
Expand All @@ -115,22 +115,22 @@ function Main() {
const user = getUser(sessionID);

useEffect(() => {
console.log("reached interactivity!");
console.log("已达到交互状态!");
}, []);

return (
<main>
Hello, {user.name}!
<button onClick={() => console.log("hydrated!")}>
Clicking me requires hydration.
你好,{user.name}
<button onClick={() => console.log("已完成 hydration!")}>
点击此按钮需要先完成 hydration
</button>
</main>
);
}

function Shell({ children }) {
// In a real app, this is where you would put your html and body.
// We're just using tags here we can include in an existing body for demonstration purposes
// 在真实应用中,你应在此处放置 html body
// 这里只是为了演示,使用可以包含在现有 body 中的标签。
return (
<html>
<body>{children}</body>
Expand All @@ -141,18 +141,18 @@ function Shell({ children }) {
function App() {
return (
<Shell>
<Suspense fallback="loading header">
<Suspense fallback="正在加载页眉">
<Header />
</Suspense>
<Suspense fallback="loading main">
<Suspense fallback="正在加载主体">
<Main />
</Suspense>
</Shell>
);
}

async function main(frame) {
// Layer 1
// 第 1 层
const controller = new AbortController();
const prerenderedApp = prerender(<App />, {
signal: controller.signal,
Expand All @@ -163,31 +163,30 @@ async function main(frame) {
}
},
});
// We're immediately aborting in a macrotask.
// Any data fetching that's not available synchronously, or in a microtask, will not have finished.
// 我们会立即在宏任务中止该过程。
// 任何无法同步获取或无法在微任务中获取的数据,都不会完成加载。
setTimeout(() => {
controller.abort(new Postponed());
});

const { prelude, postponed } = await prerenderedApp;
await flushReadableStreamToFrame(prelude, frame);

// Layer 2
// Just waiting here for demonstration purposes.
// In a real app, the prelude and postponed state would've been serialized in Layer 1 and Layer would deserialize them.
// The prelude content could be flushed immediated as plain HTML while
// React is continuing to render from where the prerender left off.
// 第 2 层
// 这里只是为了演示而等待。
// 在真实应用中,prelude 和 postponed 状态会在第 1 层序列化,并在这一层反序列化。
// 在 React 从预渲染中断处继续渲染的同时,prelude 内容可以立即作为普通 HTML 刷新。
await sleep(2000);

// You would get the cookies from the incoming HTTP request
// 你会从传入的 HTTP 请求中获取 cookie
resolveCookies({ sessionID: "abc" });

const stream = await resume(<App />, postponed);

await flushReadableStreamToFrame(stream, frame);

// Layer 3
// Just waiting here for demonstration purposes.
// 第 3 层
// 这里只是为了演示而等待。
await sleep(2000);

hydrateRoot(frame.contentWindow.document, <App />);
Expand All @@ -207,12 +206,12 @@ export async function flushReadableStreamToFrame(readable, frame) {
}
}

// This doesn't need to be an error.
// You can use any other means to check if an error during prerender was
// from an intentional abort or a real error.
// 这不一定要是一个错误。
// 你可以使用其他任何方式来判断预渲染期间的错误
// 是由有意中止导致的,还是实际错误。
export class Postponed extends Error {}

// We're just hardcoding a session here.
// 这里只是硬编码一个会话。
export function getUser(sessionID) {
return {
name: "Alice",
Expand All @@ -230,7 +229,7 @@ export function sleep(timeoutMS) {

</Sandpack>

### Further reading {/*further-reading*/}
### 延伸阅读 {/*further-reading*/}

Resuming behaves like `renderToReadableStream`. For more examples, check out the [usage section of `renderToReadableStream`](/reference/react-dom/server/renderToReadableStream#usage).
The [usage section of `prerender`](/reference/react-dom/static/prerender#usage) includes examples of how to use `prerender` specifically.
恢复过程的行为类似于 `renderToReadableStream`。有关更多示例,请参阅 [`renderToReadableStream` 的用法部分](/reference/react-dom/server/renderToReadableStream#usage)
[`prerender` 的用法部分](/reference/react-dom/static/prerender#usage) 包含专门介绍如何使用 `prerender` 的示例。
Loading