React SSR、Hydration 与服务端组件
用“页面生成时机 × 组件执行位置”两条轴区分 SSR、SSG、CSR、Hydration 与 React Server Components,避免把 RSC 等同于 SSR、Client Component 等同于 CSR。
[!info] related notes
- 所属 MOC: React MOC, React SSR 与 RSC MOC
- 相关概念: Hydration, React Server Components, React 服务端组件与客户端组件, CSR、SSR 与 SSG
- 框架实践: Next.js
React SSR、Hydration 与服务端组件
为什么这组概念容易混
它们都涉及“服务器先做一部分工作”,但其实回答的是不同问题。
最稳的理解方式是把问题拆成两条轴:
轴 A:页面 / Route 什么时候得到可展示结果?
Build time / Request time / Browser time
轴 B:组件实现代码需要在哪个环境执行?
Server Component / Client Component
只要先分开这两条轴,Server Component = SSR、Client Component = CSR 这类错误就不会出现。
轴 A:页面生成时机
SSG / Static Rendering
页面主要结果在构建时或再验证时生成,之后可以直接从缓存/CDN 分发。
典型场景:官网、文档、相对稳定的内容页。
SSR / Request-time Dynamic Rendering
请求到来后,服务器结合当前请求上下文、用户、cookie 或最新数据生成页面结果。
典型场景:登录后 Dashboard、用户专属页面、需要请求时信息的页面。
CSR
主要内容依赖浏览器 JavaScript 在客户端生成或通过客户端请求补齐。
典型场景:纯 SPA 或某些强交互、服务端预渲染价值较低的区域。
这一条轴的核心问题是:
内容在什么时候被准备出来?
详见 CSR、SSR 与 SSG。
轴 B:组件执行位置
Server Component
实现逻辑留在服务器,可访问数据库、Secret、文件和内部服务;组件实现 JavaScript 不作为普通客户端组件代码进入浏览器 bundle。
Client Component
需要浏览器 JavaScript runtime,可以拥有状态、effect、事件和浏览器 API。
这一条轴的核心问题是:
这段组件代码需要哪一侧的运行时能力?
两条轴如何组合
最关键的是:它们可以自由组合,而不是一一对应。
Server Component
├── Build time 执行 → Static / SSG
└── Request time 执行 → Dynamic / SSR-like rendering
Client Component
├── 初始 UI 可预渲染 → HTML 先到达,再 Hydration
└── 也可以纯客户端运行 → CSR
因此必须记住:
Server Component ≠ SSR
Client Component ≠ CSR
Hydration 位于哪里
Hydration 不是第三种渲染模式,而是:
浏览器把已经存在的服务端/静态 HTML 与客户端组件逻辑重新接起来,使事件、状态和后续更新真正生效。
所以它更像一个“接管阶段”:
Server / build
↓
HTML 已经可见
↓
Client JavaScript 加载
↓
Hydration
↓
交互区域真正接活
注意:在 RSC 架构中,不是所有 Server Component 都需要 hydration。真正需要客户端运行时的是 Client Component 边界及其客户端子树。
一个 Next.js 例子
/dashboard
DashboardPage Server Component
├── UserSummary Server Component
├── TaskList Server Component
└── ThemeSwitcher Client Component
如果这个 Dashboard 必须根据当前用户和请求时最新任务渲染:
- Route 更接近 request-time dynamic rendering / SSR。
DashboardPage、UserSummary、TaskList仍然是 Server Components。ThemeSwitcher是 Client Component。ThemeSwitcher的存在并不会让整个页面变成 CSR。
这就是两条轴真正分开的结果。
RSC Payload 为什么存在
React Server Components 不只是把一大段静态 HTML 扔给浏览器。框架还需要传递可以描述服务端组件结果、Client Component 位置和 props 等信息的 RSC 数据。
可以粗略理解为:
Server Components
↓
RSC representation / payload
+
initial HTML(首屏)
+
Client Component JS
HTML 负责尽快可见;RSC 数据帮助 React 维持组件树与后续导航;Client JavaScript 负责需要交互的部分。
与传统 SSR 的核心差异
传统 SSR 常见模式是:
整个 React tree 在服务器产 HTML
↓
整个需要交互的应用 JS 到客户端
↓
Hydrate 大片组件树
RSC 的目标之一则是进一步减少客户端需要拥有的实现代码:
Server-only component implementation
→ 留在 Server
Interactive client boundary
→ 才进入 Client JS
所以 RSC 的核心价值不是“SSR 换了个名字”,而是重新定义了 组件实现代码的分发边界。
常见误区
“SSR 页面就是 Server Component 页面”
不对。SSR 描述请求时生成;Server Component 描述执行环境。
“Client Component 就只能 CSR”
不对。Client Component 的初始 UI 仍可被服务端预渲染,随后 hydration。
“有 RSC 就不需要 hydration”
不对。Server Component 自身不需要客户端 hydration,但 Client Component 仍需要客户端 runtime 与接管过程。
“有一个 Client Component,整个 Route 就变成客户端渲染”
不对。一个 Route 可以由大量 Server Components 加少量 Client Boundaries 组成。
最短记忆模型
SSR / SSG / CSR
= 什么时候、在哪里准备页面结果
Server / Client Component
= 组件实现代码需要哪一侧运行时
Hydration
= 已有 HTML 如何接上客户端交互
面试时若只记一句:
先分清“页面何时生成”和“组件在哪里执行”,再讨论 SSR、RSC 与 Hydration。