← [ BACK_TO_NOTES ]

React 服务端组件与客户端组件

React Server/Client Component 的执行环境、能力边界与组合规则;重点区分组件执行位置与 SSR/CSR 渲染模式。

#frame #react #synthesis #growing

[!info] related notes

React 服务端组件与客户端组件

核心结论

Server Component 与 Client Component 首先回答的是:

这段组件代码需要在哪个运行环境中具备能力?

  • Server Component:组件逻辑留在服务器;适合数据读取、Secret、服务端资源和不依赖浏览器交互的 UI 组织。
  • Client Component:需要客户端 JavaScript runtime;适合事件、局部状态、effect、浏览器 API 与即时交互。

这不是“后端组件 vs 前端页面”的二选一,而是同一棵 UI 树里的执行边界。

Server-first 判断法

在支持 RSC 的框架(例如 Next.js App Router)中,一个稳健的默认策略是:

默认保持 Server Component
        ↓
是否真的依赖浏览器能力?
   ├─ 否 → 继续留在 Server
   └─ 是 → 建立 Client Boundary

因此判断组件归属时,不要看“它是不是显示在浏览器里”,而要看“它依赖什么能力”。

只显示 UI 仍然可以是 Server Component

例如:

function BMIResult({ bmi }: { bmi: number }) {
  return <p>BMI: {bmi}</p>
}

它最终当然显示在浏览器里,但组件本身不需要 useState、事件或浏览器 API,所以没有理由为了“显示 UI”而变成 Client Component。

能力边界

能力Server ComponentClient Component
普通 JSX / props 展示✅✅
服务端数据库 / Secret✅❌
服务端文件系统 / 内部服务✅❌
async/await 服务端数据读取✅视客户端请求而定
useState / useEffect❌(客户端状态/effect)✅
onClick / onChange❌✅
window / document / localStorage❌✅

这里的重点不是死记 API,而是识别 runtime capability。

"use client" 是模块边界,不是“纯 CSR 开关”

在 Next.js App Router 中:

"use client"

更准确地表示:

从这里开始建立一个需要客户端 JavaScript runtime 的模块边界。

它并不等于:

这个组件只能在浏览器第一次生成 HTML

Client Component 的初始 UI 仍然可以被服务器预渲染,之后再 hydration。因此:

Client Component ≠ CSR
Server Component ≠ SSR

组件执行位置与页面生成时机是两个维度,详见 React SSR、Hydration 与服务端组件。

一个用户动作可以同时跨 Client 与 Server

例如“保存 Assessment”经常被误判成纯 Client 或纯 Server。

真实边界更像:

用户点击 Save
      ↓
Client Component
负责 onClick / 表单交互
      ↓
Server Action / HTTP Mutation
负责权限、校验、业务逻辑
      ↓
Database

因此:

  • 交互触发属于客户端能力。
  • 数据库写入属于服务端能力。

不要要求一个组件标签同时替代整个请求链路的架构分析。

Server → Client 的数据边界

Server Component 可以把数据作为 props 交给 Client Component:

// Server Component
export default async function Page() {
  const user = await getUser()
  return <ProfileEditor initialName={user.name} />
}
"use client"

export function ProfileEditor({ initialName }: { initialName: string }) {
  const [name, setName] = useState(initialName)
  // ...
}

跨过 Server → Client 边界的数据需要适合 React/框架的序列化协议。数据库连接、Secret、任意服务端实例不应该被当作 props 传入客户端。

为什么要缩小 Client Boundary

把没有交互需求的实现留在服务器,通常可以减少:

  • 客户端 JavaScript bundle
  • JS parse / execute 成本
  • hydration 范围
  • 不必要的客户端数据请求

这和 Islands Architecture 有相似目标,但机制不同:Astro 强调 HTML-first 的独立岛屿 hydration;RSC 保持统一 React Tree,通过 Server/Client Component boundary 决定代码去向。

常见误区

“显示在浏览器里,所以是 Client Component”

错误。UI 最终显示在哪里,和组件实现代码在哪里执行不是一回事。

“有按钮,所以整个页面都应该 use client”

错误。通常只需要让最小的交互子树成为 Client Component。

“Server Component 就是 SSR”

错误。Server Component 可以在构建时运行,也可以在请求时运行。

“Client Component 就是 CSR”

错误。Client Component 可以先得到服务端预渲染的 HTML,再 hydration 获得交互能力。

最短记忆方式

Server = 数据、资源、组合
Client = 状态、事件、浏览器

再补一句更准确的工程判断:

先问这段代码需要哪一侧的能力,再决定边界;不要用“页面看起来像前端还是后端”来分类。

创建于 2026/3/19 更新于 2026/10/17
Digital Biome
Access

键盘导航

j / k / ↑ / ↓
选择对象
Enter / o
打开选择
/ 或 Ctrl+K
全站搜索
i / f / 1–4
筛选当前列表
g → h / l / p / t / a
首页 / 笔记 / 项目 / 工具 / About
r → 1–9
打开所选对象的关联
u
返回上一页
Esc
关闭浮层 / 取消命令;输入框内清空文本