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

相关推荐
洋流几秒前
0基础进大厂,React框架基础篇:创建你的第一个React框架项目——梦开始的地方
react.js
阿星做前端几秒前
聊聊前端请求拦截那些事
前端·javascript·面试
阿凤215 分钟前
在UniApp中防止页面上下拖动的方法
前端·uni-app
拾光拾趣录13 分钟前
DocumentFragment:高性能DOM操作
前端·dom
LZD_jay37 分钟前
在服务器(ECS)部署 MySQL 操作流程
服务器·数据库·mysql
Ronin30539 分钟前
【Linux系统】进程控制
linux·运维·服务器·ubuntu
归于尽39 分钟前
从JS到TS:我们放弃了自由,却赢得了整个世界
前端·typescript
palpitation971 小时前
Fitten Code使用体验
前端
byteroycai1 小时前
用 Tauri + FFmpeg + Whisper.cpp 从零打造本地字幕生成器
前端
用户1512905452201 小时前
C 语言教程
前端·后端