选择性水合与 HTML 流式传输
使用 Suspense 边界传输 HTML 片段,并优先水合可交互的岛屿。
选择性水合与 HTML 流式传输 是 CoddyKit 上的免费 React Academy 课时。 这是第 3 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 React Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 React Academy 课程共包含 4 节课。
整页水合的问题
传统 SSR 会一次性对整页进行水合。如果页面的一部分包含大量 JavaScript(例如地图或图表),就会阻塞其余部分的水合,包括简单的交互式按钮。
使用 renderToPipeableStream 流式传输 HTML
React 18 的流式接口会分块发送 HTML。页面外壳会立即到达;Suspense 边界会在内容解析后逐步填充,用户无需等待所有数据就绪即可看到用户界面。
const { pipe } = renderToPipeableStream(<App />, {
bootstrapScripts: ['/bundle.js'],
onShellReady() {
res.setHeader('content-type', 'text/html');
pipe(res);
},
onError(error) {
console.error(error);
},
});流式渲染在实践中的工作方式
React 会立即渲染不会暂停的组件(外壳)。当 Suspense 边界的数据解析后,React 会发送一个 HTML 块来填充该边界,并附带一个脚本标签,指示浏览器将其放置到相应位置。
选择性水合
使用流式渲染时,React 18 可以独立地对组件进行水合。如果用户点击了尚未完成水合的元素,React 会优先对该组件进行水合,然后继续处理其余部分。
将 Suspense 边界作为流式传输单元
每个 <Suspense> 边界都是一个流式传输单元。回退内容会立即发送,实际内容稍后再以流的形式传输。嵌套 Suspense 边界,以便按合适的粒度进行流式传输。
function App() {
return (
<Layout>
{/* Streams first — no data needed */}
<Header />
<Suspense fallback={<ArticleSkeleton />}>
{/* Streams when article data resolves */}
<Article />
</Suspense>
<Suspense fallback={<CommentsSkeleton />}>
{/* Streams independently from Article */}
<Comments />
</Suspense>
</Layout>
);
}Next.js 中使用 loading.tsx 进行流式传输
在 Next.js 应用路由器中,loading.tsx 就是 Suspense 回退内容。页面外壳(布局)会先进行流式传输;页面内容会在其异步函数解析后进行流式传输。
// app/blog/loading.tsx — shown while page.tsx data loads
export default function Loading() {
return <ArticleSkeleton />;
}
// app/blog/page.tsx — fetches data, streams when ready
export default async function BlogPage() {
const posts = await fetchPosts(); // data fetch happens server-side
return <PostList posts={posts} />;
}Suspense 中的客户端组件
服务端组件使用 Suspense 进行数据流式传输。客户端组件使用 Suspense 进行延迟加载。两者都能从选择性水合中受益。
// Lazy-loaded client component — hydrates selectively
const HeavyChart = lazy(() => import('./HeavyChart'));
function Dashboard() {
return (
<Suspense fallback={<ChartSkeleton />}>
<HeavyChart />
</Suspense>
);
}基于优先级的水合
如果用户与尚未完成水合的组件进行交互(例如点击它),React 18 会先同步水合该组件,然后再完成页面其他部分的水合。
onShellReady 与 onAllReady
当外壳(未被挂起的部分)准备好进行流式传输时,会触发 onShellReady。当所有内容都渲染完成时,会触发 onAllReady——这适用于静态生成,或您必须一次性发送完整 HTML 的场景。
// For streaming (progressive rendering):
onShellReady() { pipe(res); }
// For full HTML (e.g., static export, SEO bots):
onAllReady() { pipe(res); }Abort 控制器
将 AbortController 信号传入,以取消执行缓慢的 SSR(例如超过超时限制时)。
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 5000); // 5s timeout
const { pipe } = renderToPipeableStream(<App />, {
signal: controller.signal,
onShellReady() { pipe(res); },
});
clearTimeout(timeoutId);衡量流式传输的影响
使用 Lighthouse 或 WebPageTest,在启用流式传输前后测量首字节时间(TTFB)和最大内容绘制(LCP),以量化改进效果。
快速检查
在 React 18 的选择性水合中,如果用户点击了一个尚未完成水合的元素,会发生什么?
回顾
流式 SSR 使用 renderToPipeableStream 和 Suspense 边界逐步发送 HTML。每个 Suspense 边界都可以独立进行流式传输。选择性水合会优先处理用户交互过的元素。在 Next.js 中,loading.tsx 是页面级流式传输的自动 Suspense 回退内容。
常见问题解答
「选择性水合与 HTML 流式传输」课时是免费的吗?
是的 — 「选择性水合与 HTML 流式传输」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 React Academy 课程的其余内容,请升级到 CoddyKit PRO。 React Academy 课程共包含 4 节课。
「选择性水合与 HTML 流式传输」这节课中我会学到什么?
使用 Suspense 边界传输 HTML 片段,并优先水合可交互的岛屿。 你通过在浏览器中直接运行的动手代码来练习 React Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 React Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 React Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 3 节课,共 4 节。
「选择性水合与 HTML 流式传输」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 React Academy 课中编写并运行代码吗?
能。每节 React Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。
此课程中的所有课时
- React SSR 的底层工作原理
- 水合错误:原因与修复
- 选择性水合与 HTML 流式传输
- 岛屿架构模式