第一性原理
前端 UI 交付方式的演化,本质上只围绕一对矛盾在推进:
更快首屏展示 vs 更低客户端负担
每一代方案都在解决上一代带来的新问题,同时尽可能不放大另一端的代价。
第一阶段:CSR(纯客户端渲染)
原理
服务端只返回一个空的 HTML 壳子 + 一个巨大的 JS bundle。浏览器下载 JS → 执行 → 渲染出 UI。
解决了什么
- 服务端几乎没有压力
- 页面切换完全由前端路由控制,体验“像 App”
代价
- 首屏慢:用户要等 JS 下载、解析、执行完才能看到内容
- SEO 差:爬虫拿到的是空白页
第二阶段:SSR(服务端渲染)
原理
服务端直接执行 React 等框架,生成完整的 HTML 返回给浏览器。
解决了什么
- 首屏很快:用户立即看到内容
- SEO 友好:爬虫直接获取有意义的 HTML
新问题
HTML 只是静态快照,没有交互能力——按钮不能点,输入框没反应。
第三阶段:Hydration(水合)
原理
浏览器先显示服务端给的 HTML,然后加载 JS,再让 React 在客户端重新跑一遍渲染,把虚拟 DOM 与现有 HTML 对齐,最后绑定事件。
解决了什么
- 让 SSR 生成的页面恢复交互能力
代价(本质问题)
- 重复计算:服务端 render 一次,客户端再 render 一次
- 必须完全一致:稍有不匹配就报 Hydration Mismatch
- JS 体积不变:客户端仍需完整 React 运行时 + 所有组件代码
矛盾开始显现:既然客户端还要完整跑一遍,那 SSR 的意义是什么?
第四阶段:Partial Hydration(部分水合 / 岛屿架构)
原理
不是所有 UI 都需要交互。静态文本、商品描述等组件不参与 hydration,只有按钮、输入框等“交互岛”才被水合。
解决了什么
- 减少客户端需要执行的水合工作量
- 降低部分 JS 体积(按组件拆分)
遗留问题
静态组件对应的 JS 代码仍然会被下载——只是没有执行水合。能不能让它们完全不下发?
第五阶段:RSC(React Server Components)
原理
将组件明确分为两类:
- Server Component:只在服务器运行,直接访问数据库,输出 UI 描述。相关代码完全不打包到客户端。
- Client Component:负责交互的部分(useState、onClick 等),才会被水合。
解决了什么(本质突破)
UI 不再需要在客户端重新计算
| 对比维度 | Hydration 模式 | RSC 模式 |
|---|---|---|
| 服务端角色 | 生成 HTML 快照 | 直接输出 UI 结果 |
| 客户端角色 | 重建整个 UI | 只负责交互部分 |
| 静态组件 JS | 必须下载 | 完全不下载 |
| 重复渲染 | 有(客户端再算一次) | 无 |
使用场景
- 内容型页面(博客、电商商品详情、仪表盘)
- 需要直接访问后端数据的组件
- 对首屏性能和 JS 体积敏感的应用
整条链路速览
| 阶段 | 核心思路 | 解决的问题 | 带来的新代价 |
|---|---|---|---|
| CSR | 客户端全量渲染 | 服务端无压力 | 首屏慢、SEO 差 |
| SSR | 服务端生成 HTML | 首屏快、SEO 好 | 没有交互 |
| Hydration | 客户端重建并绑定事件 | 恢复交互 | 重复渲染、全量 JS |
| Partial Hydration | 只水合交互组件 | 减少水合范围 | 静态组件代码仍下发 |
| RSC | 静态组件完全不下发 JS | 彻底消除重复计算 | 需要区分 Server/Client 边界 |
为什么这是趋势
前端的核心瓶颈已经从“渲染速度”转向“JS 执行成本”。在弱网、低端设备上,下载和解析 JS 的开销远大于渲染本身。RSC 这类方案的本质就是三件事:
- 减少 JS 体积
- 减少重复执行
- 减少客户端计算
它不只是一个性能优化技巧,而是一个模型层面的转向:最好的代码,就是不需要在客户端跑的代码。