文章目录
- 前言
-
-
- [1. 什么是服务器组件 (Server Components)?](#1. 什么是服务器组件 (Server Components)?)
- [2. 服务器组件的核心规则](#2. 服务器组件的核心规则)
-
- [(1) 异步性 (`async/await`)](#(1) 异步性 (
async/await
)) - [(2) 无客户端交互](#(2) 无客户端交互)
- [(3) 渲染限制](#(3) 渲染限制)
- [(1) 异步性 (`async/await`)](#(1) 异步性 (
- [3. 与客户端组件的协作](#3. 与客户端组件的协作)
-
- 组合模式
- [Props 传递规则](#Props 传递规则)
- [4. 使用场景](#4. 使用场景)
- [5. 文件命名约定](#5. 文件命名约定)
- [6. 常见误区](#6. 常见误区)
- [7. 示例代码](#7. 示例代码)
- 关键总结
-
前言
React 官方文档中 server-components
页面详细解释了 React 服务器组件 (RSC) 的核心概念、规则和使用场景。以下是该页面的核心内容解析:
1. 什么是服务器组件 (Server Components)?
- 运行环境 :仅在服务端执行,不会将组件代码(JSX、逻辑、依赖)发送到客户端。
- 目的 :
- 减少客户端 JS 体积,提升加载性能。
- 直接访问服务端资源(数据库、API、文件系统)。
- 自动代码分割,避免手动优化。
- 输出 :将渲染后的 UI 描述(非可交互 JS) 发送给客户端,类似 HTML 流。
2. 服务器组件的核心规则
(1) 异步性 (async/await
)
- 所有服务器组件必须是
async
函数 ,可使用await
直接获取数据:
js
async function MyServerComponent() {
const data = await fetchData(); // 直接访问数据库/API
return <div>{data}</div>;
}
js
export default async function RootLayout({ children, params }) {
const resolvedParams = await params;
const { serializedResources } = await getTranslation(resolvedParams.locale, "common");
// ...渲染逻辑
}
这里直接在组件体内用 await 获取服务端数据,然后将数据传递给子组件。
(2) 无客户端交互
- 禁止使用 Hooks :如
useState
,useEffect
,useContext
等。 - 无浏览器 API :无法访问
window
,document
,localStorage
。 - 无事件处理 :不能定义
onClick
,onChange
等交互逻辑。
Server Component(服务器组件):
- 只能在服务器端渲染,不能包含如 useState、useEffect、事件处理(如 onClick)等客户端交互逻辑。
- 不能访问浏览器 API(如 window、document)。
- 只能通过 props 向下传递数据,不能响应用户在浏览器中的直接操作。
- 适合做数据获取、服务端渲染、静态内容输出等。
Client Component(客户端组件):
- 以 'use client' 开头,可以使用 React 的所有客户端特性(如 useState、useEffect、事件处理等)。
- 可以访问浏览器 API。
- 适合做交互、动画、表单、按钮等需要响应用户操作的内容。
(3) 渲染限制
-
只能返回 可序列化数据 或 客户端组件 :
js// ✅ 合法:传递数据给客户端组件 function ServerComponent() { return <ClientComponent data={...} />; } // ❌ 非法:直接渲染浏览器 API 相关组件 function InvalidComponent() { return <input onChange={...} />; // 事件处理只能在客户端 }
3. 与客户端组件的协作
组合模式
- 服务器组件可作为 父组件 渲染客户端组件:
js
// ServerComponent.server.js
import ClientComponent from './ClientComponent.client';
export default function ServerComponent() {
return (
<div>
<h1>服务端渲染</h1>
<ClientComponent /> {/* 嵌套客户端组件 */}
</div>
);
}
html
<I18nProviderWrapper locale={resolvedParams.locale} initialResources={serializedResources}>
{children}
</I18nProviderWrapper>
src/components/I18nProviderWrapper.tsx 是一个客户端组件(文件顶部有 'use client'),它被服务器组件 layout.tsx 作为子组件直接渲染。符合 Next.js 推荐的分层架构(Server Component 作为父,Client Component 作为子)
Props 传递规则
- 传递给客户端组件的 props 必须是 可序列化的 :
- ✅ 基本类型:
string
,number
,boolean
- ✅ 简单对象/数组
- ✅ JSX(作为 children)
- ❌ 函数、类实例、Symbol 等不可序列化数据。
- ✅ 基本类型:
4. 使用场景
适合服务器组件 | 适合客户端组件 |
---|---|
数据获取(DB/API) | 交互逻辑(表单、动画) |
静态内容渲染 | 使用 Hooks(状态、副作用) |
敏感逻辑(访问密钥) | 浏览器 API(localStorage) |
减少客户端 JS 体积 | 事件处理(onClick 等) |
5. 文件命名约定
- 服务端组件:
*.server.js
(或.server.jsx
,.server.tsx
) - 客户端组件:
*.client.js
(或.client.jsx
,.client.tsx
) - 通用组件:无后缀,但需在客户端组件中显式导入。
6. 常见误区
- 误区 :"服务端组件可替代 SSR"。
- 纠正 :RSC 与 SSR 互补:
- SSR:将客户端组件初始 HTML 快速渲染到浏览器。
- RSC:在服务端生成静态内容,减少客户端负担。
- 纠正 :RSC 与 SSR 互补:
- 误区 :"服务器组件可处理用户交互"。
- 纠正:交互必须交给客户端组件处理。
7. 示例代码
服务端组件(获取数据):
js
// ProductDetails.server.js
async function ProductDetails({ id }) {
const product = await db.products.get(id); // 直接访问数据库
return (
<div>
<h1>{product.name}</h1>
<p>{product.description}</p>
<ProductImage image={product.image} /> {/* 客户端组件 */}
</div>
);
}
客户端组件(处理交互):
js
// ProductImage.client.js
'use client'; // 标记为客户端组件
function ProductImage({ image }) {
const [zoomed, setZoomed] = useState(false);
return (
<img
src={image.url}
onClick={() => setZoomed(!zoomed)}
className={zoomed ? 'zoomed' : ''}
/>
);
}
关键总结
特性 | 服务器组件 | 客户端组件 |
---|---|---|
执行环境 | 服务端 | 浏览器 |
数据获取 | 直接访问后端资源 | 通过 fetch /API 调用 |
交互性 | ❌ 无事件处理/状态 | ✅ 支持所有交互逻辑 |
代码发送到客户端 | ❌ 仅发送渲染结果 | ✅ 发送完整 JS 代码 |
减少 JS 体积 | ✅ 显著优化 | ❌ 增加客户端负担 |
通过合理组合 Server Components(内容) + Client Components(交互),可构建高性能的 React 应用。建议结合 Next.js App Router 实践以体验完整 RSC 工作流。