react-server-components

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

React Server Components

React Server Components

React's Server Components enable modern UX with a server-driven mental model. This is quite different from Server-side Rendering (SSR) of components and results in significantly smaller client-side JavaScript bundles.
React的Server Components支持以服务端驱动思维模型实现现代用户体验。这与组件的Server-side Rendering (SSR)有很大不同,能显著减小客户端JavaScript包的体积。

When to Use

适用场景

  • Use this when you want to reduce client-side JavaScript by running data-fetching and rendering on the server
  • This is helpful for improving performance with zero-JS-cost server-rendered components in Next.js 13+ App Router
  • 当你希望通过在服务端运行数据获取和渲染逻辑来减少客户端JavaScript时,可使用该方案
  • 这有助于在Next.js 13+ App Router中通过零JS成本的服务端渲染组件提升性能

Instructions

使用说明

  • Use Server Components (default in frameworks like Next.js App Router) for data fetching and non-interactive UI
  • Add
    'use client'
    directive only to components that need interactivity (event handlers, state, effects)
  • Server Components can use heavy libraries (markdown parsers, date formatters) at zero client bundle cost
  • Server Components complement SSR — they are not a replacement for it
  • Use Server Functions or Server Actions (
    'use server'
    ) for form submissions and mutations when your framework supports them
  • 对于数据获取和非交互式UI,使用Server Components(在Next.js App Router等框架中为默认选项)
  • 仅对需要交互性的组件(包含事件处理程序、状态、副作用)添加
    'use client'
    指令
  • Server Components可以使用重型库(如markdown解析器、日期格式化工具)且不会增加客户端包体积
  • Server Components是对SSR的补充,而非替代
  • 当你的框架支持时,使用Server Functions或Server Actions(
    'use server'
    )处理表单提交和数据变更

Details

详细说明

Update (React 19 / modern frameworks): React Server Components are now a production feature for framework users. Unlike classic SSR, RSCs let you render part of your UI on the server without shipping that component's JavaScript to the client. The Container/Presentational pattern is a strong fit here: the "container" can be a Server Component that fetches data and passes it to an interactive Client Component.
In Next.js App Router, you no longer use
getServerSideProps
—instead, any React component in the
app/
directory can be async to fetch data on the server. React Server Components are not a replacement for SSR—they complement it. You typically use RSC for the majority of the page (rendered and streamed as part of SSR), and add
'use client'
directives for components that need interactivity.
The
'use server'
directive is for Server Functions or Server Actions, not for marking a component as a Server Component. Server Components have no directive; they are the default in frameworks that support them unless you opt into
'use client'
.
React Server Components are now production-ready in frameworks like Next.js App Router. The following resources are the most useful starting points:
更新(React 19 / 现代框架): React Server Components现已成为框架用户可用的生产级功能。与传统SSR不同,RSCs允许你在服务端渲染部分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 Component无需指令;在支持它的框架中,除非你选择使用
'use client'
,否则默认就是Server Component。
React Server Components现已在Next.js App Router等框架中支持生产环境使用。以下是最实用的入门资源:

Server-side rendering limitations

服务端渲染的局限性

Today's Server-side rendering of client-side JavaScript can be suboptimal. JavaScript for your components is rendered on the server into an HTML string. This HTML is delivered to the browser, which can appear to result in a fast First Contentful Paint or Largest Contentful Paint.
However, JavaScript still needs to be fetched for interactivity which is often achieved via a hydration step. Server-side rendering is generally used for the initial page load, so post-hydration you're unlikely to see it used again.
Note: While it's true that one could build a server-only React app leveraging SSR and avoiding hydrating on the client at all, heavy interactivity in the model often involves stepping outside of React. The hybrid model that Server Components enable will allow deciding this on a per-component basis.
With React Server Components, our components can be refetched regularly. An application with components which rerender when there is new data can be run on the server, limiting how much code needs to be sent to the client.
[RFC]: Developers constantly have to make choices about using third-party packages. Using a package to render some markdown or format a date is convenient for us as developers, but it increases code size and hurts performance for our users
Before Server Components, using a markdown renderer and sanitizer would add to the bundle:
js
// *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 */);
}
如今基于客户端JavaScript的服务端渲染可能并非最优方案。组件的JavaScript在服务端渲染为HTML字符串,该HTML被传递到浏览器,看似能实现快速的首次内容绘制(First Contentful Paint)或最大内容绘制(Largest Contentful Paint)。
然而,为了实现交互性,仍需要获取JavaScript,这通常通过 hydration(水合)步骤完成。服务端渲染通常仅用于初始页面加载,水合完成后就很少再使用。
注意: 虽然理论上可以构建一个仅使用SSR且完全避免客户端水合的纯服务端React应用,但这种模式下的复杂交互往往需要脱离React。Server Components支持的混合模型允许你基于每个组件来决定是否采用客户端交互。
使用React Server Components,我们的组件可以定期重新获取数据。当有新数据时重新渲染组件的应用可以在服务端运行,从而限制需要发送到客户端的代码量。
[RFC原文]:开发者经常需要权衡是否使用第三方包。使用包来渲染markdown或格式化日期对开发者来说很方便,但会增加代码体积并影响用户体验
在Server Components出现之前,使用markdown渲染器和清理工具会增加包体积:
js
// *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

Server Components

React's new Server Components complement Server-side rendering, enabling rendering into an intermediate abstraction format without needing to add to the JavaScript bundle. This both allows merging the server tree with the client tree without losing state and enables scaling up to more components.
Server Components are not a replacement for SSR. When paired together, they support quickly rendering in an intermediate format, then having Server-side rendering infrastructure rendering this into HTML enabling early paints to still be fast. We SSR the Client components which the Server components emit, similar to how SSR is used with other data-fetching mechanisms.
This time however, the JavaScript bundle will be significantly smaller. Early explorations have shown that bundle size wins could be significant (-18-29%), but the React team will have a clearer idea of wins in the wild once further infrastructure work is complete.
[RFC]: If we migrate the above example to a Server Component we can use the exact same code for our feature but avoid sending it to the client - a code savings of over 240K (uncompressed):
js
import marked from "marked"; // zero bundle size
import sanitizeHtml from "sanitize-html"; // zero bundle size

function NoteWithMarkdown({text}) {
  // same as before
}
React的新Server Components是对服务端渲染的补充,支持渲染为中间抽象格式,且无需添加到JavaScript包中。这既允许在不丢失状态的情况下合并服务端树和客户端树,也支持扩展到更多组件。
Server Components并非SSR的替代品。将两者结合使用时,它们支持快速渲染为中间格式,然后通过服务端渲染基础设施将其转换为HTML,从而仍能实现快速的早期绘制。我们对Server Components输出的Client组件进行SSR,这与SSR和其他数据获取机制的配合方式类似。
不过,此时JavaScript包的体积会显著减小。早期测试显示,包体积可大幅缩减(-18-29%),但React团队需要完成更多基础设施工作后,才能明确实际场景中的收益。
[RFC原文]:如果我们将上述示例迁移到Server Component,我们可以使用完全相同的代码实现功能,但无需将其发送到客户端——节省了超过240K的未压缩代码:
js
import marked from "marked"; // zero bundle size
import sanitizeHtml from "sanitize-html"; // zero bundle size

function NoteWithMarkdown({text}) {
  // same as before
}

Automatic Code-Splitting

自动代码分割

It's been considered a best-practice to only serve code users need as they need it by using code-splitting. This allows you to break your app down into smaller bundles requiring less code to be sent to the client. Prior to Server Components, one would manually use
React.lazy()
to define "split-points" or rely on a heuristic set by a meta-framework, such as routes/pages to create new chunks.
Before Server Components:
js
// *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} />;
  }
}
Some of the challenges with code-splitting are:
  • Outside of a meta-framework (like Next.js), you often have to tackle this optimization manually, replacing
    import
    statements with dynamic imports.
  • It might delay when the application begins loading the component impacting the user-experience.
Server Components introduce automatic code-splitting treating all normal imports in Client components as possible code-split points. They also allow developers to select which component to use much earlier (on the server), allowing the client to fetch it earlier in the rendering process.
With Server Components:
js
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出现之前,开发者需要手动使用
React.lazy()
定义“分割点”,或依赖元框架(如路由/页面)的启发式规则来创建新的代码块。
Server Components出现之前:
js
// *Before* Server Components
import React from "react";

// 其中一个会在客户端渲染时开始加载:
const OldPhotoRenderer = React.lazy(() => import("./OldPhotoRenderer.js"));
const NewPhotoRenderer = React.lazy(() => import("./NewPhotoRenderer.js"));

function Photo(props) {
  // 根据功能标志、登录状态、内容类型等切换:
  if (FeatureFlags.useNewPhotoRenderer) {
    return <NewPhotoRenderer {...props} />;
  } else {
    return <PhotoRenderer {...props} />;
  }
}
代码分割面临的部分挑战:
  • 除了元框架(如Next.js)之外,你通常需要手动进行这种优化,将
    import
    语句替换为动态导入。
  • 这可能会延迟应用开始加载组件的时间,影响用户体验。
Server Components引入了自动代码分割,将Client组件中的所有普通导入视为潜在的代码分割点。它们还允许开发者更早地在服务端选择要使用的组件,从而让客户端在渲染过程中更早地获取该组件。
使用Server Components:
js
import React from "react";

// 其中一个会在渲染并流式传输到客户端后开始加载:
import OldPhotoRenderer from "./OldPhotoRenderer.client.js";
import NewPhotoRenderer from "./NewPhotoRenderer.client.js";

function Photo(props) {
  // 根据功能标志、登录状态、内容类型等切换:
  if (FeatureFlags.useNewPhotoRenderer) {
    return <NewPhotoRenderer {...props} />;
  } else {
    return <PhotoRenderer {...props} />;
  }
}

Will Server Components replace Next.js SSR?

Server Components会替代Next.js SSR吗?

No. They are quite different. Initial adoption of Server Components will actually be experimented with via meta-frameworks such as Next.js as research and experimentation continue.
To summarize the differences between Next.js SSR and Server Components from Dan Abramov:
  • Code for Server Components is never delivered to the client. In many implementations of SSR using React, component code gets sent to the client via JavaScript bundles anyway. This can delay interactivity.
  • Server Components enable access to the back-end from anywhere in the tree. In older Next.js data APIs, logic often had to live in page-level functions like
    getServerSideProps()
    . With Server Components, data fetching can live closer to the component that needs it.
  • Server Components may be refetched while maintaining Client-side state inside of the tree. This is because the main transport mechanism is much richer than just HTML, allowing the refetching of a server-rendered part (e.g such as a search result list) without blowing away state inside (e.g search input text, focus, text selection)
Some of the early integration work for Server Components will be done via a webpack plugin which:
  • Locates all Client components
  • Creates a mapping between IDs => chunk URLs
  • A Node.js loader replaces imports to Client components with references to this map.
  • Some of this work will require deeper integrations (e.g with pieces such as Routing) which is why getting this to work with a framework like Next.js will be valuable.
As Dan notes, one of the goals of this work is to enable meta-frameworks to get much better.
不会。它们有很大的不同。实际上,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插件完成,该插件:
  • 定位所有Client组件
  • 创建ID => 代码块URL的映射
  • Node.js加载器将对Client组件的导入替换为对该映射的引用
  • 部分工作需要更深层次的集成(如与路由的集成),这就是为什么与Next.js这样的框架配合使用会很有价值。
正如Dan所说,这项工作的目标之一是让元框架变得更完善。

Learn more

了解更多

Source

来源