mcpField
R
react-server-components

react-server-components

github.com/patternsdev开发257967 次安装28 周前更新
代码仓库

关于 react-server-components

介绍 React Server Components 及其在服务端驱动渲染中的作用,适合希望减少客户端 JavaScript 的 React 开发者,并阐明其与 SSR、交互式客户端组件的区别。

主要功能

  1. 01在服务端获取数据并渲染
  2. 02不向客户端发送服务端组件代码
  3. 03用客户端组件实现交互
  4. 04支持自动代码拆分
  5. 05重新获取服务端片段时保留客户端状态

适用场景

  1. 01以较少客户端 JavaScript 渲染非交互界面
  2. 02将依赖浏览器的交互留给客户端组件
  3. 03刷新服务端结果而不丢失输入状态

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/patternsdev/skills --skill react-server-components

安装后在 Claude Code 中输入/react-server-components确认已加载。

详细介绍

React Server Components

目录

React 的 Server Components 支持采用服务器驱动的思维模式,打造现代化用户体验。这与组件的服务器端渲染(SSR)截然不同,并能显著缩小客户端 JavaScript 包。

适用场景

  • 想要通过在服务器上运行数据获取和渲染来减少客户端 JavaScript 时,使用此方案。
  • 这有助于借助 Next.js 13+ App Router 中零 JavaScript 成本的服务器渲染组件提升性能。

不适用场景

  • 组件需要客户端交互时——状态(useState)、副作用(useEffect)和事件处理程序都需要 Client Components。
  • 组件依赖仅限浏览器使用的 API(例如 window、localStorage、IntersectionObserver)时。
  • 组件本身已经很小,而服务器与客户端的边界带来的复杂性超过了它所节省的成本时。

说明

  • 使用 Server Components(在 Next.js App Router 等框架中默认启用)获取数据并构建非交互式 UI。
  • 仅对需要交互的组件(事件处理程序、状态、副作用)添加 'use client' 指令。
  • Server Components 可以使用重量级库(Markdown 解析器、日期格式化工具),而不会增加客户端包的开销。
  • Server Components 与 SSR 相辅相成,并非替代 SSR。
  • 如果框架支持,使用 Server Functions 或 Server Actions('use server')处理表单提交和数据变更。

详情

更新(React 19 / 现代框架): 对于框架用户来说,React Server Components 现已成为正式版功能。与传统 SSR 不同,RSC 允许你在服务器上渲染部分 UI,而无需将该组件的 JavaScript 发送到客户端。容器/展示组件模式非常适合这种场景:“容器”可以是一个 Server Component,用于获取数据并将其传递给可交互的 Client Component。

在 Next.js App Router 中,你不再使用 getServerSideProps——取而代之的是,app/ 目录中的任何 React 组件都可以是异步组件,以便在服务器上获取数据。React Server Components 并非 SSR 的替代方案,而是与之相辅相成。通常,你会将 RSC 用于页面的大部分内容(作为 SSR 的一部分进行渲染和流式传输),并为需要交互的组件添加 'use client' 指令。

'use server' 指令用于 Server Functions 或 Server Actions,而不是用来将组件标记为 Server Component。Server Components 无需指令;在支持它们的框架中,它们是默认选项,除非你选择使用 'use client'。

React Server Components 现已在 Next.js App Router 等框架中达到生产就绪状态。以下资源最适合作为入门指南:

服务端渲染的局限性

如今,客户端 JavaScript 的服务端渲染效果可能并不理想。组件的 JavaScript 会在服务器上渲染为 HTML 字符串。浏览器收到这段 HTML 后,可能会因此更快地显示首次内容绘制或最大内容绘制。

不过,为了实现交互性,仍然需要获取 JavaScript,这通常通过水合步骤实现。服务端渲染通常用于初次加载页面,因此水合完成后,基本不会再次用到它。

注意: 虽然确实可以构建一个仅在服务器端运行的 React 应用,利用 SSR 并完全避免在客户端进行水合,但模型中的复杂交互通常需要跳出 React。Server Components 支持的混合模式,可以让你针对每个组件分别做出选择。

借助 React Server Components,我们可以定期重新获取组件。包含在有新数据时会重新渲染的组件的应用可以在服务器上运行,从而减少需要发送到客户端的代码量。

在 Server Components 出现之前,使用 Markdown 渲染器和净化器会增加打包体积:

// *Before* Server Components
import marked from "marked"; // 35.9K (11.2K gzipped)
import sanitizeHtml from "sanitize-html"; // 206K (63.3K gzipped)

function NoteWithMarkdown({text}) {
  const html = sanitizeHtml(marked(text));
  return (/* render */);
}
Server Components

React 的新功能 Server Components 是对服务端渲染的补充,它们可以将内容渲染为中间抽象格式,而无需增加 JavaScript 包的体积。这样既可以在不丢失状态的情况下合并服务器树和客户端树,也能支持扩展到更多组件。

Server Components 并不能取代 SSR。二者配合使用时,可以先快速渲染为中间格式,再由服务端渲染基础设施将其渲染为 HTML,从而确保首次绘制仍然足够快。我们会对 Server Components 输出的客户端组件进行 SSR,类似于 SSR 与其他数据获取机制的搭配方式。

不过,这样生成的 JavaScript 包会显著变小。早期探索显示,打包体积有望大幅缩小(-18-29%),但 React 团队要等后续基础设施工作完成后,才能更准确地了解实际效果。

import marked from "marked"; // zero bundle size
import sanitizeHtml from "sanitize-html"; // zero bundle size

function NoteWithMarkdown({text}) {
  // same as before
}
自动代码拆分

最佳实践一直是通过代码拆分,只在用户需要时才提供所需代码。这样可以将应用拆分成更小的包,减少发送到客户端的代码量。在 Server Components 出现之前,人们通常会手动使用 React.lazy() 定义“拆分点”,或依赖元框架(例如路由/页面)设置的启发式规则来创建新的代码块。

在 Server Components 出现之前:

// *Before* Server Components
import React from "react";

// one of these will start loading *when rendered on the client*:
const OldPhotoRenderer = React.lazy(() => import("./OldPhotoRenderer.js"));
const NewPhotoRenderer = React.lazy(() => import("./NewPhotoRenderer.js"));

function Photo(props) {
  // Switch on feature flags, logged in/out, type of content, etc:
  if (FeatureFlags.useNewPhotoRenderer) {
    return <NewPhotoRenderer {...props} />;
  } else {
    return <PhotoRenderer {...props} />;
  }
}

代码拆分的一些挑战:

  • 如果不使用元框架(如 Next.js),通常必须手动处理这项优化,将 import 语句替换为动态导入。
  • 这可能会延迟应用开始加载组件的时间,影响用户体验。

Server Components 引入了自动代码拆分机制,将客户端组件中的所有常规导入都视为潜在的代码拆分点。它们还允许开发者更早地(在服务器上)选择要使用的组件,使客户端能够在渲染过程的更早阶段获取该组件。

使用 Server Components 时:

import React from "react";

// one of these will start loading *once rendered and streamed to the client*:
import OldPhotoRenderer from "./OldPhotoRenderer.client.js";
import NewPhotoRenderer from "./NewPhotoRenderer.client.js";

function Photo(props) {
  // Switch on feature flags, logged in/out, type of content, etc:
  if (FeatureFlags.useNewPhotoRenderer) {
    return <NewPhotoRenderer {...props} />;
  } else {
    return <PhotoRenderer {...props} />;
  }
}
Server Components 会取代 Next.js SSR 吗?

不会。它们截然不同。随着研究和实验的继续,Server Components 的早期应用实际上会通过 Next.js 等元框架进行探索。

Dan Abramov 总结了 Next.js SSR 和 Server Components 之间的区别:

  • Server Components 的代码永远不会发送到客户端。 在许多使用 React 实现 SSR 的方案中,组件代码仍会通过 JavaScript 包发送到客户端。这可能会延迟交互。
  • Server Components 支持在组件树的任意位置访问后端。 在较早的 Next.js 数据 API 中,逻辑通常必须放在页面级函数中,例如 getServerSideProps()。使用 Server Components 时,数据获取逻辑可以放在更靠近所需组件的位置。
  • 重新获取 Server Components 时,可以保留组件树内部的客户端状态。 这是因为主要传输机制比单纯的 HTML 丰富得多,因此可以重新获取服务器渲染的部分内容(例如搜索结果列表),而不丢失其内部状态(例如搜索框中的文本、焦点和文本选区)。

Server Components 的部分早期集成工作将通过 webpack 插件完成,该插件会:

  • 定位所有客户端组件
  • 创建 ID => 分块 URL 的映射
  • Node.js 加载器会将对客户端组件的导入替换为对此映射的引用。
  • 其中一些工作需要更深入的集成(例如与路由等部分的集成),因此让它能够与 Next.js 这样的框架协同工作会很有价值。

正如 Dan 所指出的,这项工作的目标之一是让元框架变得更好。

来源

参考资料

评论

支持 Markdown