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 calledprerenderwith. For example, a JSX element like<App />. It is expected to represent the entire document, so theAppcomponent should render the<html>tag. -
postponedState:从 预渲染 API 返回的不透明postpone对象,从存储它的任何位置加载(例如,Redis、文件或 S3)。¥
postponedState: The opaquepostponeobject 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-srcContent-Security-Policy 脚本的nonce字符串。¥optional
nonce: Anoncestring to allow scripts forscript-srcContent-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
resumesuccessfully 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.allReadybefore 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调用。你还可以手动将引导内容注入可写流。¥
resumedoes not accept options forbootstrapScripts,bootstrapScriptContent, orbootstrapModules. Instead, you need to pass these options to theprerendercall that generates thepostponedState. You can also inject bootstrap content into the writable stream manually. -
resume不接受identifierPrefix,因为前缀在prerender和resume中必须相同。¥
resumedoes not acceptidentifierPrefixsince the prefix needs to be the same in bothprerenderandresume. -
由于无法将
nonce提供给预渲染,因此如果你不提供脚本来提供预渲染,则应仅提供nonce至resume。¥Since
noncecannot be provided to prerender, you should only providenoncetoresumeif you’re not providing scripts to prerender. -
resume从根节点重新渲染,直到找到未完全预渲染的组件。只有完全预渲染的组件(组件及其子组件已完成预渲染)才会被完全跳过。¥
resumere-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.