🌗 RSC 与前后端边界模糊

一句话定性

RSC(React Server Components)是整部”跨端与全栈”史的当代终点。过去前后端的边界是一次网络请求——显眼、可见、在 Network 面板里。RSC 把这条边界搬进了组件树:“这个组件在服务端跑、那个在客户端跑”成了组件级的决定,边界变成了组件树里一条看不见的线。前端不再”调用后端”,而是直接”写一段在服务端运行的 UI”。这是范式转变,也是复杂度被内化到极致的一刻。


一、它是什么 & 出现的时代

2020 年 React 团队公布 RSC 构想,随 React 18+(以及 Next.js App Router)逐步落地。它的核心是一种新的组件分类:

组件分裂为两个世界

  Server Component (默认)          Client Component ("use client")
  ────────────────────────        ──────────────────────────────
  在服务端运行 / 渲染               在浏览器运行
  可直接 await 数据库 / 文件         可用 useState / useEffect / 事件
  零客户端 JS(不进 bundle)        会被打包进 bundle, 有交互
         │                                  ▲
         └──── 在同一棵组件树里交织 ─────────┘
// 这是一个 Server Component —— 直接在组件里 await 数据库, 这段代码永不发往浏览器
async function ProductPage({ id }) {
  const product = await db.product.find(id);   // 后端代码, 写在"组件"里
  return (
    <article>
      <h1>{product.name}</h1>
      <AddToCart id={id} />   {/* 这是 Client Component, 有交互, 才进 bundle */}
    </article>
  );
}

取数不再是”组件挂载后发一个请求”(useEffect + fetch),而是组件本身就在服务端、可以直接 await 数据源。 数据获取被吸进了渲染本身。

它生于 2023-未来 AI时代 的开端,是 全栈框架与BFF 演化的下一站、渲染模式演进史 的最新形态。


二、为什么会出现(解决上一代什么痛点)

客户端渲染 + 全栈框架留下的未竟之痛

  1. SPA 的原罪还没根治:把渲染和取数全搬到客户端,带来巨大的 JS bundle、白屏、瀑布式请求(组件挂载→请求→再渲染子组件→再请求)。详见 React 的”四、副作用”。
  2. 取数与组件割裂:数据”属于”哪个组件、在哪取、怎么传,一直是 React 的老大难。状态管理、数据请求库满天飞,本质都是在弥补”组件无法直接拿数据”这个缺口。
  3. 全栈框架虽顺滑,边界仍在: tRPC 让前端能方便地调用后端,但你心里始终有一条”这是前端、那是后端、中间隔着一次网络请求”的线。每次取数仍是一次显式的跨边界往返。

RSC 的回答是一次更激进的取消:既然前后端都在一套 React + TypeScript 里,为什么取数还要”发请求”?让一部分组件干脆就在服务端运行、直接读数据库,把渲染好的结果(连同零 JS)送到客户端不就行了?

这是 跨端与全栈演进史 母题的逻辑终点

全栈化一路把后端往前端项目里搬:Node → API routes → BFF → tRPC,每一步都让那条网络边界更顺滑。RSC 是这条路的尽头——不是让边界更好穿越,而是让边界从”系统之间”消失到”组件之间”。


三、核心机制 & 为什么(被认为是)范式转变

为什么说它是范式转变,而不只是一次优化

过去三十年,前后端的分界线一直架在网络协议上:HTTP 请求/响应是那道清晰的关卡。无论 SSR、SSG、BFF、tRPC 怎么变,“客户端”和”服务端”始终是两个用网络隔开的世界。

RSC 第一次把这条线画进了组件树内部:

         <App>                    ← Server
           ├─ <Nav>               ← Server(直接读配置/DB)
           ├─ <ProductPage>       ← Server(await 数据库)
           │     └─ <AddToCart>   ← Client("use client", 有交互)
           └─ <Footer>            ← Server
  ─────────────────────────────────────────────────────
    边界不再是"一次网络请求", 而是组件树里 Server/Client 的交界线

同一棵组件树,横跨服务端和客户端,边界是树里一条根据 "use client" 划出的线。 你写组件时就在决定”这段在哪运行”。这是对”前端 = 浏览器里跑的东西”这个三十年定义的根本改写——组件成了横跨前后端的统一抽象单位。

与 Server Actions 配合,连”提交表单/写数据”也能写成一个在服务端运行的函数,直接在组件里调用——读和写都不再显式跨网络。

为什么能落地

  • 全栈框架的铺路:前后端已经在同一个项目、同一种语言、同一套类型里(见 全栈框架与BFF),RSC 才有土壤。
  • 渲染演进的累积:从 CSR→SSR→SSG→Streaming,服务端渲染基础设施已经成熟,RSC 是其上的新形态。
  • 打包/序列化能力:框架能在构建期切分 Server/Client 组件、流式传输渲染结果。

四、带来的新问题 / 副作用

边界没有消失,只是从"系统间"内化进了"一行代码"

  1. 隐形边界 = 新心智负担:过去看 Network 面板就知道前后端在哪交接;现在边界藏在组件树里,一个不小心在 Server Component 里用了 useState、或在 Client Component 里 import 了数据库,就会炸。“这段到底在哪跑”成了每行代码都要在脑子里维护的状态。
  2. 认知分裂(cognitive split):Server / Client 两种组件能力不同(能 await DB vs. 能用 Hooks)、序列化规则不同(props 必须可序列化才能跨边界传)、错误信息晦涩。这是 React 在 Hooks 之后又一次抬高了入门曲线。
  3. “复杂度守恒”的又一次印证:RSC 没有消灭前后端的复杂度,只是把它从”两个系统、一次请求”压缩进了”一棵树、一条线”。复杂度变得更隐蔽,也因此更难教、更难调试。
  4. 生态与心智的撕裂期:大量为 CSR 设计的库(“use client” 才能用)、对 RSC 的误用、框架(主要是 Next.js App Router)与 React 本体的耦合争议——生态还在剧烈适应。
  5. 强绑定全栈与部署:RSC 默认你有一个能跑组件的服务端/边缘环境,把前端进一步绑死在全栈与特定部署形态上。

第一性原理拷问:把”前后端边界”从可见的网络请求,变成不可见的组件树分界线,究竟是降低了认知负担,还是只是把它藏起来了? 这是 RSC 最大的争议,目前没有定论。


五、为什么会衰落 / 现状

RSC 仍处在早期、争议中、快速演进的阶段,远谈不上衰落,但也远未被普遍接受:

  • 被押注为 React 的未来主轴:Next.js App Router 默认 RSC,React 官方明确将其作为下一代默认范式。
  • 争议激烈:社区对”复杂度、心智负担、与框架的耦合、是否真的解决了问题”分歧很大。一部分人转向更简单的范式(回到岛屿架构 islands、或 SvelteKit/SolidStart 等更轻的全栈方案)。
  • 与 Edge / 全栈 / 数据获取深度融合:RSC + Server Actions + Streaming + Edge 部署,正在被打包成”一站式全栈渲染”的现代方案(详见 渲染模式演进史)。
  • AI 时代的叠加变量:在 2023-未来 AI时代,“心智负担高”的代价可能被 AI 部分吸收(AI 帮你管 Server/Client 边界),也可能因为”边界太隐蔽 AI 也容易出错”而成为新麻烦——见 未来5到10年前端发展方向

六、对后续技术的影响(因果链)

SPA 原罪(白屏/bundle/瀑布请求) + 取数与组件割裂 + 全栈框架"边界仍在"
        │
        ↓
全栈化铺路: [[Node.js]] → API routes → BFF → tRPC(前后端同项目/同语言/同类型)
        │   见 [[全栈框架与BFF]]
        ↓
RSC(React 18+, ~2023): 组件分裂为 Server / Client
        │   边界从"网络请求"下沉为"组件树里的一条线"
        │
        ├─► 组件成为横跨前后端的统一抽象单位 ──► 范式转变
        │       └─► 取数被吸进渲染(组件里直接 await)
        │
        ├─► + Server Actions ──► 读/写都不再显式跨网络
        │
        ├─► 副作用: 隐形边界 + 认知分裂 + 复杂度内化(守恒, 只是更隐蔽)
        │
        └─► 与 Edge / 数据获取 / 部署融合
                │
                ├─► [[渲染模式演进史]](RSC 是渲染演进的最新形态)
                ↓
        前后端边界彻底模糊 ──► 前端"领土扩张"的逻辑终点
                │
                ↓
        AI 时代变量 ──► [[未来5到10年前端发展方向]]

历史地位

RSC 是 跨端与全栈演进史 母题——“前端用一套 JS/TS 技能栈吞噬相邻领域”——的逻辑终点。它把”前端 vs. 后端”这个三十年的二分法,从”网络两端的两个系统”压缩成了”同一棵组件树里的一条线”。如果它成功,“前端”和”后端”作为分立工种的意义将被根本改写;如果它失败,人们会记得这是前端扩张冲得最远的一次,并从中学到”复杂度无法被消灭,只能被转移”这一课。无论哪种结局,它都标记了前端领土扩张抵达的最远疆界。


🔗 同组:跨端与全栈演进史 | 全栈框架与BFF | React-Native与移动跨端 | 小程序生态 | Electron与桌面端 🔗 框架:React | Vue | 前端框架演进史 | Angular-2+ 🔗 渲染:渲染模式演进史 | 运行时:Node.js | Deno | Bun | 语言:TypeScript 🔗 时代:2018-2023 工程化时代 | 2023-未来 AI时代 | 深度:未来5到10年前端发展方向