React Server Components(RSC)

React 的服务端组件架构,允许组件在服务端执行并将序列化的 UI 描述(RSC Payload)发送到客户端。Server Components 不下载 JS、不水合,从根本上减少了客户端 JS 量。通过 'use client' 指令划分服务端/客户端边界。

核心概念

React Server Components(RSC)重新定义了"组件在哪里执行"这个问题。传统 SSR 中,所有组件都在服务端执行一次(生成 HTML)、在客户端再执行一次(水合)。RSC 引入了一个根本性的区分:

  • Server Components(默认):只在服务端执行,输出序列化的 UI 描述(RSC Payload),不发送组件的 JS 代码到客户端,不需要水合
  • Client Components'use client' 标记):在服务端预渲染 + 在客户端水合,行为与传统 React 组件一致

关键区别:RSC 的服务端组件输出的不是 HTML 字符串,而是一种可流式传输的序列化格式(RSC Payload)——本质上是 React 元素树的 JSON 化表示。客户端的 React 运行时接收这个 payload 并将其集成到组件树中,无需执行服务端组件的 JS 代码。

Server / Client 边界

jsx
// ServerComponent.jsx — 默认是 Server Component
// 可以直接 async/await、访问数据库、读文件系统
async function ArticlePage({ id }) {
  const article = await db.articles.find(id);  // 直接查数据库
  return (
    <article>
      <h1>{article.title}</h1>
      <p>{article.content}</p>
      <CommentSection articleId={id} />  {/* Client Component */}
    </article>
  );
}

// CommentSection.jsx
'use client';  // 标记为 Client Component
// 可以使用 useState、useEffect、事件处理等
function CommentSection({ articleId }) {
  const [comments, setComments] = useState([]);
  // ...交互逻辑
}

边界规则

  • Server Component 可以导入和渲染 Client Component
  • Client Component 不能导入 Server Component(但可以通过 children prop 接收 Server Component 的渲染结果)
  • 跨越边界传递的 props 必须是可序列化的(和 Qwik 的 Resumability 约束类似)

对 SSR 水合成本的影响

RSC 从根本上减少了需要水合的组件数量。一个典型的内容页面可能 80% 是 Server Components(标题、正文、导航),只有 20% 需要交互(搜索框、评论区)——水合成本从 O(所有组件) 降到 O(可交互组件)

这和 Islands Architecture 的目标一致,但实现路径不同:

  • Islands(Astro):显式用 client:* 指令标记交互组件,框架无关
  • RSC(Next.js):用 'use client' 指令标记客户端边界,依赖 React 生态,Server/Client Components 共享同一棵 React 树

Server Actions('use server'

RSC 不仅改变了数据获取模式(Server Component 直接查数据库),还引入了 Server Actions 来处理数据变更:

jsx
// Server Action
'use server';
async function submitComment(formData) {
  await db.comments.create({ text: formData.get('text') });
  revalidatePath('/article');
}

Server Action 被编译为一个 RPC 端点——客户端调用时自动发送 HTTP 请求到服务端执行函数体,不需要手动写 API 路由。这是一种编译器驱动的全栈抽象——开发者写的是一个函数,编译器拆分成客户端的 fetch 调用和服务端的处理逻辑。

与 Qwik Resumability 的对比

维度RSCQwik Resumability
核心目标减少客户端 JS(部分组件不发送 JS)消灭水合(所有组件都不需要重新执行)
交互组件的处理Client Components 仍需传统水合事件处理函数按需懒加载,不水合
序列化约束跨边界 props 必须可序列化所有闭包变量必须可序列化
生态耦合React 专属Qwik 专属

两者可以视为同一问题的两种解法:"如何避免在客户端执行不必要的 JS?"RSC 的答案是"部分组件根本不发到客户端",Qwik 的答案是"发到客户端但不立即执行"。

引用本术语的文章