next.js 16 水合问题

发布时间:2026/5/27 5:56:48

next.js 16 水合问题 你提出了一个非常深刻且直击核心的问题你提到的use client意味着我们现在讨论的是 Next.js 的App RouterRSC 架构。你的直觉完全正确服务器确实没有把服务器组件Server Components的 JS 代码发给浏览器浏览器手里只有客户端组件Client Components的 JS Chunks。那为什么两者的虚拟 DOM 树还能对得上不会触发水合错误呢因为 Next.js 在这里玩了一个极其硬核的“魔术”服务端传给浏览器的除了 HTML还有一份绝密的数据文件——RSC PayloadReact 服务端组件载荷。 浏览器收到的到底是什么当访问一个包含服务器组件和客户端组件的页面时Next.js 服务端会并行生成并发送三样东西给浏览器HTML 结构供浏览器快速渲染让用户肉眼看到网页。JS Chunks仅仅包含带有use client的客户端组件的交互逻辑。RSC Payload这是一串特殊的、序列化的文本数据你可以把它理解为一个超级线索文件。什么是 RSC Payload它用一种特殊的 JSON 格式完整记录了整棵组件树的结构和所有服务器组件渲染后的最终结果。举个例子假设你有一个服务器组件里面包裹了一个客户端组件// 服务器组件 (Server Component) export default function ArticlePage() { return ( div classNamecontainer h1文章标题/h1 {/* 静态内容 */} LikeButton / {/* 客户端组件 use client */} /div ) }对于这段代码服务端绝对不会把ArticlePage的 JS 发给浏览器但它会在RSC Payload里写下这样一份“结构描述说明书”“报告浏览器 React 运行时整棵树的根是一个div类名叫container它下面有一个h1里面的文本是‘文章标题’再往下是一个占位符对应的是客户端组件LikeButton这个组件的 JS 代码在chunk-abc123.js里。” 客户端 React 运行时是如何构建虚拟 DOM 的当浏览器的 React 运行时Runtime启动时它并不是单纯地去运行那些 JS Chunks而是把 JS Chunks 和 RSC Payload 结合起来看React 读取RSC Payload说明书。看到div和h1React 说“知道了这是服务器组件留下的静态结构。” 于是直接在内存的虚拟 DOM 树中画出div和h1。看到LikeButton占位符React 说“噢这里需要客户端交互。” 于是它去翻看下载好的JS Chunks把LikeButton的核心逻辑、事件监听器onClick拿过来插进刚刚构建的虚拟 DOM 树的对应位置。最终结果React 仅仅利用“RSC Payload 说明书”“客户端 JS Chunks”就在浏览器内存中完美复刻出了完整的虚拟 DOM 树因为这棵虚拟 DOM 树的骨架完全是按照服务器给的说明书RSC Payload画出来的所以它和服务器生成的 HTML 结构100% 严丝合缝。水合顺利通过完全不会报错 架构可视化我们可以通过下面的对比图看清 React 客户端运行时是如何利用两股数据合流完美还原虚拟 DOM 的3. 水合比对2. 浏览器客户端运行时1. 服务端生成并发送快速呈现读取静态骨架注入动态逻辑与事件比对结构比对结构完美的相同1. 静态 HTML 壳子包含所有文字和标签2. RSC Payload 说明书包含整棵树的结构描述3. 客户端 JS Chunks仅包含 use client 组件用户肉眼看到的界面React 尝试构建客户端虚拟 DOM是否一致?✅ 水合成功! 页面可交互 总结你之所以产生怀疑是因为在传统 React 单页应用中“代码 (JS)”等于“结构 (DOM)”。但在 Next.js 的 RSC 架构中“结构”已经和服务端组件的代码分离了。服务器组件的代码留在了后端它的“结构”变成了RSC Payload发给了前端只有客户端组件的代码才作为JS Chunks发给前端。React 运行时聪明地利用 RSC Payload 织出了整棵树的皮肤再用 JS Chunks 激活了局部的器官从而实现了完美的、无报错的水合。

相关新闻