React 服务器组件 (RSC)

文章目录

  • 前言
      • [1. 什么是服务器组件 (Server Components)?](#1. 什么是服务器组件 (Server Components)?)
      • [2. 服务器组件的核心规则](#2. 服务器组件的核心规则)
        • [(1) 异步性 (`async/await`)](#(1) 异步性 (async/await))
        • [(2) 无客户端交互](#(2) 无客户端交互)
        • [(3) 渲染限制](#(3) 渲染限制)
      • [3. 与客户端组件的协作](#3. 与客户端组件的协作)
      • [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:在服务端生成静态内容,减少客户端负担。
  • 误区 :"服务器组件可处理用户交互"。
    • 纠正:交互必须交给客户端组件处理。

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 工作流。

相关推荐
gnip1 小时前
首页加载、白屏优化方案
前端·javascript
思扬09281 小时前
前端学习日记 - 前端函数防抖详解
前端·学习
gnip1 小时前
包体积,打包速度优化
前端·javascript
正义的大古2 小时前
Vue 3 + TypeScript:深入理解组件引用类型
前端·vue.js·typescript
A5rZ2 小时前
缓存投毒进阶 -- justctf 2025 Busy Traffic
前端·javascript·缓存
未来之窗软件服务3 小时前
浏览器CEFSharp133+X86+win7 之多页面展示(三)
前端·javascript·浏览器开发·东方仙盟
阿雄不会写代码3 小时前
Amazon Linux 训练lora模型的方式
linux·运维·服务器
胡斌附体3 小时前
elementui cascader 远程加载请求使用 选择单项等
前端·javascript·elementui·cascader·可独立选中单节点
烛阴3 小时前
Vector Normaliztion -- 向量归一化
前端·webgl
孟陬4 小时前
写一个 bun 插件解决导入 svg 文件的问题 - bun 单元测试系列
react.js·单元测试·bun