SSR 渲染和 RSC 组件的区别
更新: 7/27/2026字数: 0 字 时长: 0 分钟
在理解了 SSR(服务端渲染)之后,学习 RSC(React Server Components,React 服务端组件) 就会非常轻松。
很多人容易把它们混淆,以为 RSC 是 SSR 的替代品,但事实并非如此:RSC 不是 SSR 的替代品,而是一种全新的“代码架构模式”。它们完全可以(也经常)结合在一起使用。
1. 核心定义:什么是 RSC?
简单来说:RSC 允许你把 React 组件拆分成两类——“只在服务器运行的组件”和“在浏览器运行的组件”。
在 RSC 架构下,组件被严苛地分为两类:
- 服务端组件(Server Component):只在服务器上运行,代码永远不会下载到浏览器。它可以直接在组件里读数据库、读取文件系统或请求内部 API。因为它不需要发给浏览器,所以它的依赖库(无论多大)都不占用前端 JS Bundle 的体积。
- 客户端组件(Client Component):就像我们平时写的普通 React 组件,会在浏览器运行,拥有状态(
useState)、生命周期(useEffect)和用户交互事件(onClick)。在 Next.js (App Router) 中,需要在文件顶部显式声明'use client'。
2. RSC 与 SSR 的本质区别
如果用一句话概括它们的区别:
- SSR 处理的是“页面/请求级别”的渲染流程(把 HTML 送给浏览器)。
- RSC 处理的是“组件级别”的代码分割与执行位置(决定哪部分代码留在服务器,哪部分发给客户端)。
我们从 4 个维度进行对比:
| 维度 | SSR(服务端渲染) | RSC(React 服务端组件) |
|---|---|---|
| 本质属性 | 一种页面加载与渲染策略 | 一种组件架构与代码分割模式 |
| 返回的内容 | HTML 字符串 | 专用的 RSC Payload(一种定制的 JSON 结构),用于描述 UI 树 |
| 客户端水合 (Hydration) | 必须水合(整页下载 JS 并绑定事件) | 服务端组件无需水合(因为根本没有发 JS 给客户端) |
| JS Bundle 体积 | 页面用到的所有组件代码全都要发给客户端 | 服务端组件的代码零字节发送给客户端 |
| 运行节点 | 仅在 首屏页面请求(HTML 阶段) 时运行一次 | 在整个应用生命周期中随时运行(比如客户端路由切换时重新请求 RSC) |
3. 为什么有了 SSR,还需要 RSC?(解答 SSR 的痛点)
回顾之前文章讨论的 SSR,传统的 SSR 虽然解决了“首屏白屏”和“SEO”问题,但它有一个致命的隐患:JS Bundle 体积大,水合开销高。
传统 SSR 的局限:
在传统 SSR 中,虽然服务器生成了 HTML,但所有组件的代码(JS)依然要打包发送给浏览器。
例子: 你的页面有一个“Markdown 渲染组件”,里面用了庞大的
marked.js库(比如 100KB)。
- 在 SSR 下:服务器用
marked生成了 HTML 文本送给浏览器,但为了客户端后续能够激活(Hydration),marked这个 100KB 的 JS 库依然要下载到用户的手机上。- 在 RSC 下:你把这个组件声明为 Server Component。服务器直接把 Markdown 转换成 UI 结构,
marked这个库完全留在服务器,0 字节发送给客户端!
4. RSC 与 SSR 是如何协同工作的?
在现代主流框架(如 Next.js App Router)中,RSC 和 SSR 通常是组合使用的。
我们看它们在页面首次加载和后续客户端跳转时的配合流程:
=== 场景一:用户首次访问页面 (RSC + SSR 结合) ===
[1] 用户请求页面 URL
│
▼
[2] Node.js 服务端运行 Server Components (RSC)
(直接在服务器读取数据库/调用 API,不下载第三方大库给客户端)
│
▼
[3] 生成 RSC Payload (包含服务端组件的 UI 结构 + 客户端组件的位置)
│
▼
[4] 触发 SSR:将 RSC Payload 转化为真实的 HTML 文本
│
▼
[5] 返回 HTML 给浏览器 (用户秒看到界面,FCP)
│
▼
[6] 浏览器只下载“客户端组件”的 JS 进行 Hydration (水合)
(水合开销和 JS 体积大幅减少!)
=== 场景二:用户在页面内点击链接跳转 (纯 RSC 模式,不再触发 SSR) ===
[1] 用户点击 `<Link>` 跳转到新页面
│
▼
[2] 浏览器向服务器发起 fetch 请求 (请求新页面的 RSC 数据)
│
▼
[3] 服务器只运行新页面的 Server Components,返回新页面的 RSC Payload
│
▼
[4] 客户端 React 收到 RSC Payload,无缝将新组件切入当前 DOM 树
(无需重新加载全页 HTML,也不会丢失当前页面未改变的状态!)举例:
一个在日常开发中最简单、最常见的例子,就是“网页顶部的顶部导航栏(Header)”或“用户信息卡片”。
我们可以看看一个网页最上方的“用户信息头像框”在两种模式下的巨大差异:
场景:网页顶部的“用户信息卡片”
这个卡片需要做两件事:
- 显示信息:显示用户的名字、头像、积分(纯展示)。
- 交互功能:点击头像弹下拉菜单、点击“退出登录”按钮(交互)。
1. 在传统 SSR 下(全量打包)
在传统 SSR 中,服务器渲染出这个卡片后,这个卡片里的所有 JS 代码都要打包发给客户端。
- 问题在于:为了让那个“下拉菜单”能点击,浏览器不仅下载了下拉菜单的点击逻辑,还被迫下载了用于格式化名字、格式化积分数字、处理头像默认图等一堆纯展示逻辑的 JS 代码。
- 结果:客户端要对整个卡片的所有 DOM 节点都做一遍“水合(Hydration)”。
2. 在 RSC(React 服务端组件)下(精准拆分)
在 RSC 中,你可以把这个简单的卡片拆成两层:
- 外层的卡片主体(Server Component): 在服务器直接读数据库/API 拿到用户名和头像,渲染成静态结构。这里的格式化逻辑、数据读取逻辑 0 字节发送给客户端,客户端也无需水合。
- 里层的“下拉菜单按钮”(Client Component
'use client'): 只有这个控制菜单展开/收起的几十行控制代码会被打包发给客户端。
对比
- 传统 SSR:为了让菜单能点开,把整个卡片的全部代码都发给了手机。
- RSC:只把“打开菜单”这一个动作的代码发给手机,剩下的用户名、头像等纯静态结构完全留在服务器,手机零负担。
5. 总结
- SSR 是“先在服务器把整页 HTML 做出来送给浏览器”,解决的是首屏慢和 SEO 问题。
- RSC 是“把组件分成服务端和客户端两类”,解决的是 JS 包太大、水合太慢、组件无法直接读数据库 的架构问题。
- 最佳搭档:现代 React 开发中,首屏用 SSR 把它转成 HTML 送出,内部架构用 RSC 把代码留在服务器,两者结合实现了极致的 Web 性能。