React 中的 Server Components 和 Server Components

在 React 19.2 中,React 的架构发生了根本性的转变,推行了 Server-First(服务端优先) 的理念。Server Components(服务端组件)Server Functions(服务端函数) 是支撑这一现代架构的两大核心支柱。

虽然它们都带有 "Server" 字样,但各自的分工截然不同:Server Components 负责"由内向外"的数据渲染,而 Server Functions 负责"由外向内"的行为交互


一、 React Server Components (RSC) ------ 服务端组件

1. 什么是 RSC?

React Server Components 是一种全新类型的组件,它完全在服务端运行 (可以在构建时运行,也可以在每次请求时运行)。RSC 的最大特点是:它的源代码和依赖永远不会被发送到浏览器的客户端

2. 核心优势

  • 零客户端体积(Zero Bundle Size): 如果你在 RSC 中使用了大型第三方库(如 marked 渲染 Markdown 或 sanitize-html 过滤 HTML),这些库只留在服务端,客户端不需要下载它们。
  • 直接访问后端资源: 你可以直接在组件内部编写数据库查询、读取文件系统或调用内部微服务,无需再写一套 /api/ 路由。
  • 更佳的初始加载与配置: 相比传统 SSR 仅能生成初始 HTML,RSC 还能生成一种特殊的流式数据(RSC Payload),允许客户端在不丢失当前 UI 状态的情况下,平滑地融合服务端更新。
  • 19.2 新特性增强: 在 React 19.2 中,React 优化了服务端渲染的 Suspense 边界合并流式处理(Batching Reveals)。以往流式传输时,服务端渲染的 Suspense 内容会零散地替代占位符,而 19.2 开始,React 会在短时间内批量合并显示,让首屏加载的视觉体验更丝滑、不闪烁。

3. 代码示例

tsx 复制代码
// 默认情况下(在现代支持 RSC 的框架如 Next.js 中),组件都是 Server Component
import { db } from '@/lib/db';
import marked from 'marked'; // 这个库的 JS 不会被下载到客户端

interface ArticlePageProps {
  params: { id: string };
}

export default async function ArticlePage({ params }: ArticlePageProps) {
  // 直接在组件内进行异步数据库查询
  const article = await db.article.findUnique({ where: { id: params.id } });

  if (!article) return <div>文章不存在</div>;

  const htmlContent = marked(article.content);

  return (
    <article className="prose">
      <h1>{article.title}</h1>
      {/* 直接渲染渲染好的 HTML */}
      <div dangerouslySetInnerHTML={{ __html: htmlContent }} />
    </article>
  );
}

二、 Server Functions ------ 服务端函数

1. 什么是 Server Functions?

Server Functions(在表单场景下常被称为 Server Actions )是通过 "use server" 指令标记的异步函数 。它们允许客户端代码像调用本地函数一样,直接调用运行在服务端的代码

本质上,React 在幕后为你自动构建了一个安全、类型安全的 RPC(远程过程调用) 桥梁。

2. 核心优势

  • 告别繁琐的 API 路由: 以前为了提交一个表单,你需要写 fetch('/api/submit', { method: 'POST' }) 并手动处理序列化。现在只需一个普通的异步函数。
  • 渐进式增强(Progressive Enhancement): 当与 <form action={serverFunction}> 结合使用时,即使客户端的 JavaScript 尚未加载或下载完毕,用户点击提交,表单依然可以通过传统的 HTTP POST 请求正常工作。
  • 类型安全: 从客户端传递给 Server Function 的参数在编译时是端到端类型安全的。

3. 代码示例

tsx 复制代码
// actions.ts ------ 声明服务端函数
'use server'; // 必须放在文件顶部

import { db } from '@/lib/db';
import { revalidatePath } from 'next/cache';

export async function createComment(formData: FormData) {
  const content = formData.get('commentContent') as string;
  const articleId = formData.get('articleId') as string;

  if (!content) return { error: '内容不能为空' };

  // 1. 安全地在服务端操作数据库
  await db.comment.create({
    data: { content, articleId }
  });

  // 2. 清除缓存,触发相关页面在服务端重新渲染(RSC 刷新)
  revalidatePath(`/article/${articleId}`);

  return { success: true };
}

在客户端组件(Client Component)中调用:

tsx 复制代码
// CommentForm.tsx
'use client'; // 客户端组件

import { createComment } from './actions';

export default function CommentForm({ articleId }: { articleId: string }) {
  return (
    <form action={createComment}>
      <input type="hidden" name="articleId" value={articleId} />
      <textarea name="commentContent" placeholder="说说你的看法..." />
      <button type="submit">提交评论</button>
    </form>
  );
}

三、 二者的协同工作模型

在 React 19.2 的全栈应用中,它们两者不是孤立的,而是完美闭环的。

  1. RSC(服务端组件) 在服务端获取数据,并将基础结构渲染好。
  2. 如果页面有交互(如点赞、评论),RSC 会将 Server Functions 作为 props 传递给 Client Components(客户端组件)
  3. 用户在浏览器端触发点击,Client Component 调用该 Server Function
  4. 请求飞往服务器执行,服务器更新数据库后,重新计算并生成受影响的 RSC 视图,最后将全新的 UI 片段(RSC Payload)流式发回浏览器。
  5. 客户端 React 悄无声息地局部刷新 DOM,用户甚至感觉不到页面刷新。

四、 核心区别对比

特性 React Server Components (RSC) Server Functions ('use server')
主要定位 UI 渲染 与数据读取 行为交互 与数据变更 (Mutations)
执行时机 页面加载、路由切换时在服务端运行 用户在客户端触发事件(如点击、提交)时运行
返回值 返回 React 渲染树/UI 片段 返回普通数据(JSON 序列化对象、Promise、FormData)
文件指令 默认即是(或在部分架构中无需特殊指令) 必须在顶部使用 'use server' 指令
客户端体积 依赖库 0 字节 传给客户端 函数本身转化为一个微小的 URL 请求代理

💡 避坑提示(安全与限制)

  1. 参数必须可序列化: 由于 Server Functions 需要跨越网络传输,你不能传递不可序列化的数据(例如实时的 DOM 节点、复杂的 class 实例或普通的客户端函数)。
  2. 防范越权: 即使 Server Functions 隐藏了 API 路径,它在幕后依然是个网络接口。在 React 19.2 中编写 Server Functions 时,切记要在函数内部重新校验用户的 Session 和权限 ,绝不能盲目信任客户端传过来的参数(例如 userId)。
相关推荐
光影少年15 小时前
react的 useReducer 使用场景、替代 useState 的情况
前端·react.js·掘金·金石计划
YAwu1115 小时前
原型与原型链:面试中的关键问题深入剖析
前端·javascript
To_OC15 小时前
徒手撸极简前后端分离Demo!吃透原生JS动态渲染底层
前端·javascript
HYCS15 小时前
用pixi.js实现fabric.js(四):StaticCanvas
前端·javascript·canvas
烬羽15 小时前
《读<JavaScript语言精粹>第3章,我整理了6个必须掌握的对象核心知识点》
前端
GuWenyue15 小时前
从零搭建用户管理系统!60分钟搞定RESTful接口+Bootstrap语义化首页
前端·后端
超人气王15 小时前
JavaScripts入门篇————js原型的底层原理
前端·javascript
蜡笔小电芯15 小时前
【Electron】第1章—新建工程(基于 Electron + Vite + JavaScript)
前端·javascript·electron
_xaboy15 小时前
开源Vue组件 FormCreate 使用组件内部方法校验
前端·vue.js·开源