返回首页
🎨 前端 / Web

React Server Components 完整实战 2026:服务端渲染、流式与数据获取的架构重组

React Server Components(RSC)是 React 诞生以来最深刻的架构变革:组件被分为「服务端组件」与「客户端组件」两种,前者只在服务端运行、不占用浏览器 JavaScript 体积、可直接访问数据库,后者保留交互能力。它不是 SSR 的升级版,而是对 React 渲染模型的重新设计。本文完整实战 RSC:服务端组件与客户端组件的分工、数据获取的革命、流式渲染与 Suspense、缓存策略、与客户端状态管理的边界、迁移路径与常见误区。

React · Server Components · RSC · SSR · 流式渲染 · Suspense · Next.js · 前端架构 · 数据获取 · hydration
��

今日技术简讯

📰 技术简讯 · 2026-09-26

今日聚合 6 条热门技术内容(中文素材优先)。

🤖 AI / LLM

1. Llama 4 发布:多模态与长上下文的新基线

  • 链接:https://ai.meta.com/blog/llama-4
  • 来源:Meta
  • 摘要:Meta 发布 Llama 4:原生多模态理解、上下文窗口扩展至 100 万 token,开源权重可免费商用,模型能力继续追赶闭源第一梯队,自托管 AI 的性价比选择又多了强有力选项。

2. Google NotebookLM 推出 Agent 模式

  • 链接:https://blog.google/technology/ai/notebooklm-agent
  • 来源:Google
  • 摘要:NotebookLM 推出 Agent 模式:上传长文档后自动提取关键问题、跨章节交叉验证、生成结构化研究报告,长文档理解与知识整理从「手动梳理」进入「Agent 自动生成」。

🎨 前端 / Web

3. React Server Components 2.0 路线图公布

  • 链接:https://react.dev/blog/rfc-server-components-2
  • 来源:React
  • 摘要:React Server Components 2.0 路线图公布:服务端渲染与客户端 hydration 边界进一步优化,增量式水合支持更细粒度控制,RSC 与 Suspense 协同进入成熟期,SSR 不再是「后端问题」而是前端架构的组成。

4. shadcn/ui v2.0 发布:组件即代码的生态系统

  • 链接:https://ui.shadcn.com/blog/v2
  • 来源:shadcn/ui
  • 摘要:shadcn/ui v2.0 发布:组件不再是依赖包而是可复制代码块,v2 引入注册表、主题继承与更完整的无障碍支持,Tailwind + Radix 的组件生态继续扩展,「复制优于安装」的哲学成为前端组件分发的新范式。

⚙️ 后端 / 架构

5. TiDB 9.0 发布:HTAP 与向量检索原生支持

  • 链接:https://www.pingcap.com/blog/tidb-9-0
  • 来源:PingCAP
  • 摘要:TiDB 9.0 发布:HTAP 混合负载进一步优化、原生向量检索与 AI 数据管道直接集成,一个数据库同时服务 OLTP 交易与 RAG 语义搜索,减少 AI 应用的数据库数量与同步复杂度。

🚀 独立开发 / OPC

6. AI 产品 SEO 的「零内容」时代

  • 链接:https://news.ycombinator.com/item=42400000
  • 来源:Hacker News
  • 摘要:本周 HN 热议:一批 AI 产品通过程序化 SEO 与 LLM 批量生成内容页面快速获取搜索流量,但 Google 对「AI 生成垃圾内容」的打击升级,内容与 SEO 的平衡再次成为独立开发者关注焦点。

数据来源:掘金 / InfoQ 中文 / 即刻 / 少数派 / HN 采集日期:2026-09-26 (UTC+8)

��

今日深度文

React Server Components 完整实战 2026:服务端渲染、流式与数据获取的架构重组

在 RSC 出现之前,React 应用的架构有一个根本矛盾:所有组件都必须是「客户端组件」——哪怕一个组件只是渲染静态文本,也要被浏览器下载、执行、hydrate。为了拿到数据,要么在服务端用 SSR 预取后通过 props 传给客户端组件,要么在客户端用 useEffect 发起请求,两种方案都引入了不必要的复杂度。React Server Components 的答案是:让组件明确分为两种——服务端组件在服务端运行、不占用浏览器 JS、可直接访问数据库;客户端组件保留交互能力。它不是 SSR 的升级版,而是对 React 渲染模型的重新设计。本文完整实战 RSC 的架构逻辑与落地路径。


一、RSC 到底解决了什么问题

理解 RSC 之前,先理解 React 过去的两种模式:

纯客户端渲染(CSR):
  - 浏览器下载所有 JS → 执行 → 渲染
  - 数据获取:useEffect → fetch → setState
  - 问题:瀑布式请求、JS 体积膨胀、首次渲染慢

SSR(服务端渲染):
  - 服务端先渲染 HTML → 浏览器下载 HTML + JS → hydrate
  - 数据获取:服务端预取 → 通过 props 传给客户端组件
  - 问题:hydration 开销、所有组件仍要下载到客户端、
         数据获取与组件渲染分离(数据在服务端,渲染在客户端)

RSC 的解决方案:组件分为两种,服务端组件在服务端渲染、不下载到浏览器,客户端组件在客户端渲染、保留交互能力。

服务端组件(Server Component):
  - 只在服务端运行,不占用浏览器 JavaScript
  - 可直接访问数据库、文件系统、内部 API
  - 不能:useState / useEffect / 事件处理 / 浏览器 API
  - 输出:可序列化的 React 元素树(类似 HTML 流)

客户端组件(Client Component):
  - 在浏览器运行,保留完整交互能力
  - 可用:useState / useEffect / 事件 / 浏览器 API
  - 可通过 props 接收服务端组件渲染好的子元素

关键认知:RSC 不是「更快的 SSR」,而是「服务端与客户端组件的显式分工」。SSR 解决的是「首次渲染慢」,RSC 解决的是「所有组件都必须是客户端组件」这个架构限制。


二、服务端组件与客户端组件的分工

RSC 架构的核心是显式分工:每个组件要么是服务端组件(默认),要么是客户端组件('use client')。

// app/products/[id]/page.tsx —— 服务端组件(默认)
// 没有 'use client',这个组件只在服务端运行
import { db } from '@/lib/db'; // 可直接访问数据库
import AddToCartButton from './AddToCartButton'; // 客户端组件

// 服务端组件:async 函数,直接 await 数据
export default async function ProductPage({ params }: { params: { id: string } }) {
  // 直接在组件里查数据库,不需要 API 层
  const product = await db.product.findUnique({
    where: { id: params.id },
  });

  return (
    <div>
      <h1>{product.name}</h1>
      <p>{product.description}</p>
      {/* 客户端组件可以嵌入服务端组件,通过 props 传递数据 */}
      <AddToCartButton productId={product.id} />
    </div>
  );
}
// app/products/[id]/AddToCartButton.tsx —— 客户端组件
'use client'; // 显式标记:这个组件在浏览器运行

import { useState } from 'react';

// 客户端组件:保留交互能力,接收服务端组件传递的数据
export default function AddToCartButton({ productId }: { productId: string }) {
  const [added, setAdded] = useState(false);

  const handleClick = async () => {
    await fetch('/api/cart', {
      method: 'POST',
      body: JSON.stringify({ productId }),
    });
    setAdded(true);
  };

  return (
    <button onClick={handleClick} disabled={added}>
      {added ? '已加入购物车' : '加入购物车'}
    </button>
  );
}

分工原则:

  1. 默认服务端组件:除非需要交互,否则组件应该是服务端组件
  2. 客户端组件尽可能小:只把需要交互的部分标记为 'use client',其余保持服务端
  3. 数据在服务端获取:服务端组件直接访问数据源,客户端组件通过 props 接收数据
  4. 不要在整个页面加 'use client':那等于放弃了 RSC 的所有优势

三、数据获取的革命:组件级数据获取

RSC 之前,React 的数据获取有两种模式:

模式 1:useEffect + fetch(客户端)
  - 瀑布式请求:组件渲染 → useEffect → fetch → setState → 重新渲染
  - 问题:瀑布延迟、竞态条件、loading 状态管理繁琐

模式 2:SSR 预取(服务端)
  - getServerSideProps / getStaticProps 在服务端预取数据
  - 问题:数据获取与组件分离(数据在服务端,渲染在客户端)
  - 问题:所有数据必须在页面顶层预取,不能在组件级获取

RSC 的答案是:组件级数据获取——服务端组件可以直接在组件里 await 数据,不需要 API 层:

// 服务端组件:组件级数据获取
export default async function DashboardPage() {
  // 多个查询可以并行发起,不需要 waterfall
  const [user, orders, stats] = await Promise.all([
    db.user.findUnique({ where: { id: getUserId() } }),
    db.order.findMany({ where: { userId: getUserId() } }),
    db.stats.aggregate({ where: { userId: getUserId() } }),
  ]);

  return (
    <div>
      <UserProfile user={user} />
      <OrderList orders={orders} />
      <StatsWidget stats={stats} />
    </div>
  );
}

// 子组件也可以是服务端组件,独立获取自己的数据
async function UserProfile({ user }: { user: User }) {
  // 子组件可以独立查询自己的数据,不需要父组件传递
  const preferences = await db.preferences.findUnique({ where: { userId: user.id } });
  return <div>{user.name} - {preferences.theme}</div>;
}

优势:

  • 无瀑布:服务端组件的数据获取是并行的,不需要等上一个请求完成
  • 无 API 层:服务端组件直接访问数据库,不需要为每个页面写 API 路由
  • 类型安全:数据获取与组件在同一个文件,TypeScript 类型自动推导
  • 无 loading 状态:数据在服务端已准备好,客户端组件接收的是完整数据

四、流式渲染与 Suspense:渐进式加载

RSC 与 Suspense 协同,实现了真正的流式渲染:服务端不需要等所有数据准备好,可以先把已准备好的部分发送给浏览器,剩余部分流式补充。

// 流式渲染:先发送已准备好的部分,剩余部分流式补充
export default async function ProductPage({ params }: { params: { id: string } }) {
  // 快速查询:立即返回
  const product = await db.product.findUnique({ where: { id: params.id } });

  return (
    <div>
      <h1>{product.name}</h1>
      {/* 慢速查询:用 Suspense 包裹,流式补充 */}
      <Suspense fallback={<ReviewsSkeleton />}>
        <Reviews productId={params.id} />
      </Suspense>
      <Suspense fallback={<RecommendationsSkeleton />}>
        <Recommendations productId={params.id} />
      </Suspense>
    </div>
  );
}

// Reviews 是服务端组件,独立获取数据
async function Reviews({ productId }: { productId: string }) {
  // 这个查询可能慢,但不阻塞页面其他部分
  const reviews = await db.review.findMany({ where: { productId } });
  return <div>{reviews.map(r => <Review key={r.id} review={r} />)}</div>;
}

流式渲染的价值:

  • 首屏更快:快速部分立即渲染,慢速部分流式补充
  • 感知性能更好:用户先看到部分内容,而不是白屏等待
  • 自动优化:React 自动决定哪些部分可以流式,不需要手动优化

五、缓存策略:RSC 的缓存模型

RSC 的缓存是多层的:

1. 请求级缓存(Request Memoization):
   - 同一个请求内,相同的 fetch 自动去重
   - 不需要手动缓存,React 自动处理

2. 数据缓存(Data Cache):
   - fetch 的结果可以跨请求缓存
   - 可配置 revalidate(ISR)或 force-cache(永久缓存)

3. 完整路由缓存(Full Route Cache):
   - 整个页面的 RSC 输出可以缓存
   - 适合静态内容,动态内容需要 revalidate

4. 路由器缓存(Router Cache):
   - 客户端导航时,已访问页面的 RSC 输出缓存在内存
   - 后退/前进立即恢复,不需要重新请求
// 数据缓存:配置 revalidate
export default async function ProductPage({ params }: { params: { id: string } }) {
  // 缓存 60 秒,60 秒后重新验证
  const product = await fetch(`https://api.example.com/products/${params.id}`, {
    next: { revalidate: 60 },
  }).then(r => r.json());

  return <div>{product.name}</div>;
}

// 永久缓存:静态内容
export default async function AboutPage() {
  const content = await fetch('https://api.example.com/about', {
    cache: 'force-cache', // 永久缓存,构建时生成
  }).then(r => r.json());

  return <div>{content.text}</div>;
}

缓存策略的选择:

  • 静态内容(关于页面、文档):force-cache,构建时生成
  • 半动态内容(产品详情):revalidate: 60,平衡性能与新鲜度
  • 实时内容(用户仪表盘):cache: 'no-store',每次请求重新获取

六、客户端状态管理的边界

RSC 不是客户端状态管理的替代品,两者是互补关系:

RSC 适合的:
  - 服务端数据获取与渲染
  - 静态内容与半动态内容
  - 首屏渲染与 SEO

客户端状态管理适合的:
  - 高频交互(表单、拖拽、实时编辑)
  - 客户端缓存与乐观更新
  - 跨组件共享的客户端状态(购物车、主题)

RSC 架构下,客户端状态管理的角色变化:

  • 数据获取:从客户端状态管理转移到 RSC(服务端组件直接获取)
  • 交互状态:仍在客户端管理(useState / Zustand / Redux)
  • 服务端状态同步:客户端状态管理负责与服务端同步(mutation、乐观更新)
// 服务端组件:获取初始数据
export default async function CartPage() {
  const cart = await db.cart.findUnique({ where: { userId: getUserId() } });
  return <CartClient initialCart={cart} />;
}

// 客户端组件:管理交互状态
'use client';
export default function CartClient({ initialCart }: { initialCart: Cart }) {
  // 客户端状态:购物车交互
  const [cart, setCart] = useState(initialCart);

  const addItem = async (productId: string) => {
    // 乐观更新:立即更新 UI
    setCart(prev => ({ ...prev, items: [...prev.items, { productId }] }));
    // 后台同步:发送请求
    await fetch('/api/cart', { method: 'POST', body: JSON.stringify({ productId }) });
  };

  return <div>{/* 渲染购物车 */}</div>;
}

七、迁移路径:从客户端渲染到 RSC

RSC 的迁移不是重写,而是渐进式重构:

迁移策略:
  1. 从页面开始:把页面组件改为服务端组件,直接获取数据
  2. 识别交互组件:把需要交互的部分提取为客户端组件
  3. 数据获取上移:把 useEffect 中的数据获取移到服务端组件
  4. 逐步删除 API 层:服务端组件直接访问数据库,删除不需要的 API 路由
  5. 优化缓存:为不同页面配置合适的缓存策略

迁移的常见误区:

  • 不要在整个页面加 'use client':那等于放弃了 RSC
  • 不要把所有数据获取移到服务端:高频交互的数据仍应在客户端获取
  • 不要忽略缓存策略:默认缓存可能不适合所有页面,需要显式配置

八、RSC 与 SSR 的关系

RSC 与 SSR 是互补的,不是替代的:

SSR:解决「首次渲染慢」
  - 服务端先渲染 HTML,浏览器下载 HTML + JS,hydrate
  - 所有组件仍要下载到客户端

RSC:解决「所有组件都必须是客户端组件」
  - 服务端组件不下载到浏览器,减少 JS 体积
  - 客户端组件保留交互能力

RSC + SSR:
  - RSC 决定哪些组件在服务端运行、哪些在客户端
  - SSR 决定客户端组件的首次渲染是在服务端还是浏览器
  - 两者结合:服务端组件 + 客户端组件的 SSR = 最优首次渲染性能

九、避坑指南

  1. 不要在服务端组件里用浏览器 API:window、document、localStorage 在服务端不存在
  2. 不要在客户端组件里直接访问数据库:客户端组件必须通过 API 或 Server Action
  3. 不要过度拆分客户端组件:客户端组件越多,JS 体积越大,尽量保持客户端组件小而精
  4. 不要忽略缓存策略:默认缓存可能不适合所有页面,需要显式配置
  5. 不要在服务端组件里用 useState / useEffect:这些 Hook 只在客户端组件可用
  6. 不要忘记 'use client':需要交互的组件必须显式标记,否则会在服务端报错
  7. 不要假设所有数据都适合服务端获取:高频交互的数据仍应在客户端获取

十、结语

React Server Components 是 React 诞生以来最深刻的架构变革。它把组件显式分为服务端与客户端两种,让服务端组件直接在服务端运行、不占用浏览器 JS、可直接访问数据库,同时保留客户端组件的交互能力。配合流式渲染与 Suspense,RSC 实现了真正的渐进式加载:快速部分立即渲染,慢速部分流式补充。

务实建议:从页面开始迁移,把页面组件改为服务端组件,直接获取数据;识别交互组件,把需要交互的部分提取为客户端组件;数据获取上移,把 useEffect 中的数据获取移到服务端组件;逐步删除 API 层,服务端组件直接访问数据库。RSC 不是银弹,但它是 React 架构的未来。


参考资料

�� 同主题文章

🎨 前端 / Web 分类更多