流式水合通过服务端分块渲染与客户端选择性水合,实现首屏核心区域秒响应:服务端用rendertopipeablestream边生成边传输,客户端用hydrateroot局部激活,配合资源拆分与状态一致性保障,显著缩短tti。

要缩短首屏可交互时间(TTI),关键不是让整个页面“一次激活”,而是让核心区域先活起来——流式水合正是为此而生。它把传统“全量同步 hydration”拆解为按需、分块、渐进的激活过程,配合服务端流式渲染,实现首屏按钮秒响应、滚动不卡顿。
服务端:用 renderToPipeableStream 分块输出 HTML
React 18 提供了 renderToPipeableStream(替代旧版 renderToString),支持在服务端边生成 HTML 边传输:
- 骨架内容(如页头、商品卡片结构)立即 flush,浏览器收到即渲染,TTFB 极低
- 数据依赖部分(如价格、库存、评论)封装在
<suspense fallback></suspense>中,服务端异步获取后以 chunk 形式追加发送 - 每个 chunk 包含完整语义的 HTML 片段(例如一个已带 class 和 data-id 的
<li>),客户端可直接插入 DOM
客户端:选择性水合 + 按区块挂载
客户端不再等待全部 HTML 到达才启动 hydration,而是“见块就活”:
- 使用
hydrateRoot替代hydrate,支持对任意 DOM 节点局部水合 - 首屏可见区域(如视口内前 3 个商品项)的 DOM 节点一插入,立刻调用
root.hydrate() - 非首屏组件(如页脚、推荐栏)用
React.lazy+client:only指令延迟 hydrate,或交由 IntersectionObserver 触发
边界控制:明确 hydration 的“责任范围”
避免水合失控导致主线程阻塞,需从架构层定义哪些内容必须水合、何时水合、水合到什么程度:
- 交互型组件(按钮、表单、折叠面板)必须水合;纯展示型组件(静态文案、图标 SVG)可完全服务端渲染,零 JS 体积
- 对高 CPU 开销组件(如富文本编辑器、图表)启用
useEffect(() => {}, [])延迟初始化,或用startTransition降级优先级 - 通过自定义 Hook(如
useStreamingHydration)统一管理 hydration 状态,结合useState和useTransition实现平滑过渡
配套保障:资源加载与状态协同
流式水合不是孤立技术,需与资源加载策略深度耦合:
- JS 包按区块拆分:首屏所需逻辑打包进
main.js,其余用import()动态加载,确保 hydration 不被大包阻塞 - 服务端预取关键数据:在流式响应前,提前 fetch 首屏所需 API,并将结果序列化注入 HTML 的
<script id="__NEXT_DATA__"></script>类似结构中,hydration 直接读取,免二次请求 - 状态一致性兜底:服务端与客户端初始 state 必须严格一致;建议用不可变数据结构 + JSON 序列化校验,避免 hydration mismatch 报错中断流程











