Skip to content
目录

React Server Components

1. 版本与定位

阶段说明
概念与实验React 18 起与 流式 SSR、Flight 协议在框架(如 Next.js App Router)中落地
稳定React 19 将 RSC、Server Actions、相关 bundler 约定标为稳定能力

RSC 不是「在服务器里多跑一遍 createRoot」那么简单:服务器用 React Server 渲染器产出 Flight payload(序列化组件树 + 数据引用),客户端用 React Client(Flight) 解析并挂载 Client Components,Server Component 代码默认不进浏览器 bundle

06-Suspense 的关系:服务端可对未就绪片段先流式发送 fallback,再在数据就绪后追加内容,与客户端 Suspense 协议一致。


2. Server Components vs Client Components

2.1 对比表

Server ComponentClient Component
运行环境仅服务器(构建/请求时)浏览器(+ 水合)
指令默认;无需标注文件顶 "use client"
HooksuseStateuseEffect
浏览器 APIwindowdocument
事件onClick
数据访问可直接 await DB、读文件、调内部 API通常 fetch / 调 Server Action
打包不发送组件实现到客户端发送 JS,需水合

2.2 边界怎么划(经验法则)

  • 默认 Server:纯展示、读数据、拼布局,无交互。
  • 必须 Client:状态、 effect、订阅、浏览器 API、第三方强依赖 DOM 的库。
  • 组合:Server 父组件 import Client 子组件;Client 父组件不能 import Server 子组件(只能 children 插槽由服务器注入已渲染结果)。
jsx
// Server(默认)
export default async function Page() {
  const rows = await db.query('...');
  return <Table rows={rows} />; // Table 若是 Client,仅其边界以下进 bundle
}

// Client
'use client';
export function Counter() {
  const [n, setN] = useState(0);
  return <button onClick={() => setN(n + 1)}>{n}</button>;
}

2.3 "use server" 是什么

标记 Server Actions(可在服务器执行的异步函数),供表单 action、客户端事件等调用。与「Server Component 文件」不同:Action 是函数引用经序列化传到客户端,不是整文件当组件渲染。


3. 端到端架构(无长源码)

3.1 双渲染器

包(概念)角色
react-server(Fizz 等)在 Node/Edge 上渲染 RSC,写出 Flight 流
react-client(Flight)在浏览器解析 Flight,创建 Client 组件实例并水合
react-dom仍负责 DOM 提交;与 Flight 解析结果衔接

不必记具体文件名;读源码可从 ReactFizzServer.js(服务端任务)、ReactFlightClient.jscreateFromReadableStream)入手。

3.2 一次请求的大致流程

mermaid
sequenceDiagram
  participant B as 浏览器
  participant S as 服务器 RSC
  participant F as Flight 流
  participant C as Client 运行时
  B->>S: 请求页面
  S->>S: 渲染 Server 树 await 数据
  S->>F: 序列化 chunk(含 Client 引用)
  F-->>B: 流式响应
  B->>C: 解析 Flight
  C->>C: 加载 Client 组件 JS
  C->>B: 水合交互区域
  1. 服务器执行 Server Component 树,遇 Client 组件不执行其实现,只写入 Client Reference(id + 导出名)。
  2. 序列化 props、children、懒加载边界等到 Flight 格式(非「把 React 元素 JSON.stringify」那么简单)。
  3. 客户端按引用拉取对应 JS chunk,在标记的 Client 边界内水合。
  4. 水合只发生在 Client 子树;Server 输出已是 HTML/流中的结构,减少「空壳 + useEffect 拉数据」。

3.3 和经典 SSR 的区别

经典 SSR(如 renderToStringRSC
输出主要是 HTML 字符串HTML + Flight 数据(组件树描述)
组件代码常在同一 Node bundle 执行Server / Client 分包
数据多在客户端或 getServerSideProps 重复多在 Server Component 内直接读
交互整页或大块水合仅 Client 边界水合

4. Flight 与引用系统(总结)

4.1 传什么、不传什么

可序列化(常见):原始类型、普通对象/数组、部分内置类型(Date 等,视版本与配置)、Promise(由 Suspense 流式处理)、Server Action 引用Client 组件引用

不可直接传:任意函数、类实例、Symbol、DOM 节点、window 等。Client 需要的是 引用 id,由 bundler 在构建期登记。

4.2 Client Reference / Server Reference

类型含义
Client Reference服务器渲染时占位:「这里由客户端模块 X 的导出 Y 接管」;$$typeof + $$id 等内部标记
Server ReferenceServer Action 在客户端表单/事件里可调用,实际在服务器执行;经 registerServerReference 登记

服务器不能执行 Client Reference 的函数体;客户端不能在服务器环境直接跑 Server 函数实现,只能发请求触发。

4.3 流式与 Suspense

  • 服务器渲染遇 await 或挂起:可先输出 Suspense fallback 的 HTML/Flight chunk,就绪后再发后续 chunk(流式 SSR)。
  • 与客户端 06-Suspense 同一套「未就绪 → fallback → retry」思想,避免白屏等待最慢接口。

5. Server Actions(React 19 稳定)

5.1 是什么

在服务器运行的异步函数,从 Client 以 action={fn} 或事件处理器调用;常配合 useActionStateuseFormStatus(见 04-Hooks §10)。

5.2 行为要点

说明
渐进增强<form action={serverAction}> 无 JS 也可提交(框架生成 action URL)
序列化仅传 引用 + 参数(如 FormData),不传函数源码
安全必须在服务端校验权限与输入;Action 是公开端点
与 Transition可在 Transition / Action 流程中更新 UI、useOptimistic
jsx
'use server';
export async function save(formData) {
  await db.insert(formData.get('name'));
}

// Client
'use client';
export function Form() {
  return (
    <form action={save}>
      <input name="name" />
      <button type="submit">保存</button>
    </form>
  );
}

6. 性能与使用场景

6.1 为什么能减小 bundle

  • 重型依赖(Markdown、语法高亮、大工具库)若只在 Server Component 使用,不会打进客户端 JS
  • Client 边界应尽量下移到真正需要交互的叶子,避免整页 "use client"

6.2 适合 / 不适合

适合 Server适合 Client
读 DB、读 CMS、拼静态结构表单即时校验、拖拽、动画
权限校验后读敏感数据订阅 WebSocket、媒体 API
大段只读 UI依赖 localStorage 的 UI

6.3 数据获取模式

  • 推荐:在 Server Component 里 await,结果作为 props 传给 Client 子组件。
  • 避免:在 Server 里为了「用 Hook」强行包一层 Client;也避免 Client 里 useEffect 再请求本可在服务器一次拿完的数据(除非需要浏览器隐私或实时性)。

7. 与 React 19 其它能力

能力与 RSC 关系
use客户端读由 RSC 传下的 Promise / Context
文档元数据<title> 等可在组件树中声明,由框架提升到 <head>
ref 作 prop减少 forwardRef,Client 边界组件更易组合
Actions与 Server Actions、useActionState 统一异步提交模型

详见 01-核心架构概述


8. 常见误区

  1. RSC ≠ 全站不能在客户端跑 React:只是默认在服务器渲染树;Client 岛仍需要 JS。
  2. 不是 React 19 才「发明」服务器渲染:19 是协议与生态稳定;Next 等框架在 18 已大量使用。
  3. "use client" 会向上影响导入它的模块:被 Client 引用的子模块也会进客户端包,注意依赖链。
  4. Server Component 不能传事件处理器给 Client:事件必须在 Client 组件内定义或经 Server Action 间接触发。
  5. 安全:Server Component 里访问密钥安全;绝不能把密钥或信任边界放进传给 Client 的 props。

9. 源码与框架阅读路径

关注点方向
服务端渲染任务packages/react-server — Fizz / createRequeststartWork
客户端解析流packages/react-clientcreateFromReadableStream
引用注册ReactServerReference.js、bundler 插件(框架侧)
与 DOM 衔接react-dom 流式 API:renderToReadableStream

日常开发更多接触 框架约定(Next.js app/、Server Action 文件规则)而非直接调上述底层 API。


10. 总结

  1. RSC:服务器渲染不可下发的组件树 + Flight;客户端只水合 Client 边界
  2. "use client" / "use server":划分运行环境与 Action,不是装饰语法。
  3. 流式 + Suspense:慢数据不阻塞整页首屏。
  4. Server Actions(19):类型安全的「远程过程调用 + 表单」,需服务端校验。
  5. 与并发客户端:Scheduler / Lanes 管浏览器主线程;RSC 管字节与首次 HTML——二者互补。

建议阅读顺序:02-Fiber06-Suspense → 本文 → 框架官方 RSC 文档。

参考

MIT License.