你提出了一个非常深刻且直击核心的问题!你提到的 use client 意味着我们现在讨论的是 Next.js 的 App Router(RSC 架构)

你的直觉完全正确:服务器确实没有把服务器组件(Server Components)的 JS 代码发给浏览器,浏览器手里只有客户端组件(Client Components)的 JS Chunks。

那为什么两者的虚拟 DOM 树还能对得上,不会触发水合错误呢?

因为 Next.js 在这里玩了一个极其硬核的“魔术”:服务端传给浏览器的,除了 HTML,还有一份绝密的数据文件——RSC Payload(React 服务端组件载荷)。


📦 浏览器收到的到底是什么?

当访问一个包含服务器组件和客户端组件的页面时,Next.js 服务端会并行生成并发送三样东西给浏览器:

  1. HTML 结构:供浏览器快速渲染,让用户肉眼看到网页。
  2. JS Chunks仅仅包含带有 "use client" 的客户端组件的交互逻辑。
  3. RSC Payload:这是一串特殊的、序列化的文本数据(你可以把它理解为一个超级线索文件)。

什么是 RSC Payload?

它用一种特殊的 JSON 格式,完整记录了整棵组件树的结构和所有服务器组件渲染后的最终结果

举个例子,假设你有一个服务器组件,里面包裹了一个客户端组件:

// 服务器组件 (Server Component)
export default function ArticlePage() {
  return (
    <div className="container">
      <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 结合起来看

  1. React 读取 RSC Payload 说明书。
  2. 看到 divh1,React 说:“知道了,这是服务器组件留下的静态结构。” 于是直接在内存的虚拟 DOM 树中画出 divh1
  3. 看到 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 激活了局部的器官,从而实现了完美的、无报错的水合。

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐