resume
将预渲染的 React 树流式传输到 可读网络流。
¥resume
streams a pre-rendered React tree to a Readable Web Stream.
const stream = await resume(reactNode, postponedState, options?)
参考
¥Reference
resume(node, postponedState, options?)
调用 resume
恢复将预渲染的 React 树以 HTML 形式渲染到 可读网络流。 中
¥Call resume
to resume rendering a pre-rendered React tree as HTML into a Readable Web Stream.
import { resume } from 'react-dom/server';
import {getPostponedState} from './storage';
async function handler(request, writable) {
const postponed = await getPostponedState(request);
const resumeStream = await resume(<App />, postponed);
return resumeStream.pipeTo(writable)
}
参数
¥Parameters
-
reactNode
:调用prerender
的 React 节点。例如,像<App />
这样的 JSX 元素。它应该代表整个文档,所以App
组件应该渲染<html>
标签。¥
reactNode
: The React node you calledprerender
with. For example, a JSX element like<App />
. It is expected to represent the entire document, so theApp
component should render the<html>
tag. -
postponedState
:从 预渲染 API 返回的不透明postpone
对象,从存储它的任何位置加载(例如,Redis、文件或 S3)。¥
postponedState
: The opaquepostpone
object returned from a prerender API, loaded from wherever you stored it (e.g. redis, a file, or S3). -
可选
options
:具有流选项的对象。¥optional
options
: An object with streaming options.-
可选
nonce
:允许script-src
Content-Security-Policy 脚本的nonce
字符串。¥optional
nonce
: Anonce
string to allow scripts forscript-src
Content-Security-Policy. -
可选
signal
:一个 中止信号,它允许你 中止服务器渲染 并在客户端上渲染其余部分。¥optional
signal
: An abort signal that lets you abort server rendering and render the rest on the client. -
可选
onError
:每当出现服务器错误时都会触发的回调,无论是 recoverable 还是 不。 默认情况下,这只会调用console.error
。如果你将其改写为 记录崩溃报告,,请确保你仍然调用console.error
。¥optional
onError
: A callback that fires whenever there is a server error, whether recoverable or not. By default, this only callsconsole.error
. If you override it to log crash reports, make sure that you still callconsole.error
.
-
返回
¥Returns
resume
返回一个 Promise:
¥resume
returns a Promise:
-
如果
resume
成功生成 shell,则该 Promise 将解析为 可读网络流。,然后可以通过管道传输到 可写 Web 流。。¥If
resume
successfully produced a shell, that Promise will resolve to a Readable Web Stream. that can be piped to a Writable Web Stream.. -
如果 shell 中发生错误,Promise 将拒绝该错误。
¥If an error happens in the shell, the Promise will reject with that error.
返回的流有一个额外的属性:
¥The returned stream has an additional property:
-
allReady
:一个 Promise,当所有渲染完成时解析。你可以在返回响应 用于爬虫和静态生成。 之前执行await stream.allReady
。如果这样做,你将无法获得任何渐进式加载。该流将包含最终的 HTML。¥
allReady
: A Promise that resolves when all rendering is complete. You canawait stream.allReady
before returning a response for crawlers and static generation. If you do that, you won’t get any progressive loading. The stream will contain the final HTML.
注意事项
¥Caveats
-
resume
不接受bootstrapScripts
、bootstrapScriptContent
或bootstrapModules
的选项。相反,你需要将这些选项传递给生成postponedState
的prerender
调用。你还可以手动将引导内容注入可写流。¥
resume
does not accept options forbootstrapScripts
,bootstrapScriptContent
, orbootstrapModules
. Instead, you need to pass these options to theprerender
call that generates thepostponedState
. You can also inject bootstrap content into the writable stream manually. -
resume
不接受identifierPrefix
,因为前缀在prerender
和resume
中必须相同。¥
resume
does not acceptidentifierPrefix
since the prefix needs to be the same in bothprerender
andresume
. -
由于无法将
nonce
提供给预渲染,因此如果你不提供脚本来提供预渲染,则应仅提供nonce
至resume
。¥Since
nonce
cannot be provided to prerender, you should only providenonce
toresume
if you’re not providing scripts to prerender. -
resume
从根节点重新渲染,直到找到未完全预渲染的组件。只有完全预渲染的组件(组件及其子组件已完成预渲染)才会被完全跳过。¥
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.
用法
¥Usage
恢复预渲染
¥Resuming a prerender
import { flushReadableStreamToFrame, getUser, Postponed, sleep, } from "./demo-helpers"; import { StrictMode, Suspense, use, useEffect } from "react"; import { prerender } from "react-dom/static"; import { resume } from "react-dom/server"; import { hydrateRoot } from "react-dom/client"; function Header() { return <header>Me and my descendants can be prerendered</header>; } const { promise: cookies, resolve: resolveCookies } = Promise.withResolvers(); function Main() { const { sessionID } = use(cookies); const user = getUser(sessionID); useEffect(() => { console.log("reached interactivity!"); }, []); return ( <main> Hello, {user.name}! <button onClick={() => console.log("hydrated!")}> Clicking me requires 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 return ( <html> <body>{children}</body> </html> ); } function App() { return ( <Shell> <Suspense fallback="loading header"> <Header /> </Suspense> <Suspense fallback="loading main"> <Main /> </Suspense> </Shell> ); } async function main(frame) { // Layer 1 const controller = new AbortController(); const prerenderedApp = prerender(<App />, { signal: controller.signal, onError(error) { if (error instanceof Postponed) { } else { console.error(error); } }, }); // 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. await sleep(2000); // You would get the cookies from the incoming HTTP request resolveCookies({ sessionID: "abc" }); const stream = await resume(<App />, postponed); await flushReadableStreamToFrame(stream, frame); // Layer 3 // Just waiting here for demonstration purposes. await sleep(2000); hydrateRoot(frame.contentWindow.document, <App />); } main(document.getElementById("container"));
延伸阅读
¥Further reading
恢复行为与 renderToReadableStream
相同。更多示例,请查看 renderToReadableStream
的使用部分。prerender
的使用部分 包含如何使用 prerender
的具体示例。
¥Resuming behaves like renderToReadableStream
. For more examples, check out the usage section of renderToReadableStream
.
The usage section of prerender
includes examples of how to use prerender
specifically.