发布于 2026-01-06 0 阅读
0

React 18 服务器组件深度解析

React 18 服务器组件深度解析

React 服务器组件 (RSC) 是一项极具潜力的功能,它能够显著提升页面加载性能、减小包大小,并革新我们编写 React 应用的方式。虽然这项功能在 React 18 中仍处于实验阶段,但了解其底层工作原理仍然十分重要。

服务器和客户端组件的分离

一张图表,说明了适用于服务器和客户端组件的规则。

React 服务器组件允许服务器和客户端(浏览器)协同工作来渲染你的 React 应用。React 元素树中的一些组件由服务器渲染,另一些则由浏览器渲染。这与服务器端渲染 (SSR) 不同。SSR 模拟了一个将 React 树渲染成原始 HTML 的环境,但它并不区分服务器组件和客户端组件。

React 团队根据组件所在文件的扩展名定义了服务器端组件和客户端组件:如果文件以 .server.jsx 结尾,则包含服务器端组件;如果以 .client.jsx 结尾,则包含客户端组件;如果既不以 .server.jsx 结尾也不以 .client.jsx 结尾,则包含既可用作服务器端组件也可用作客户端组件的组件。

RSC渲染器的生活

使用 RSC 的页面生命周期始终始于服务器端,服务器端会响应 API 调用来渲染 React 组件。然后,服务器会将根组件元素序列化为 JSON。最终目标是将初始的根服务器组件渲染成一个包含基本 HTML 标签和客户端组件占位符的树状结构。

然后服务器将此序列化的树发送到浏览器,浏览器可以对其进行反序列化,用实际的客户端组件填充客户端占位符,并渲染最终结果。

RSC和悬疑

Suspense 在 React 组件架构 (RSC) 中扮演着重要角色。Suspense 允许你在 React 组件需要一些尚未准备就绪的内容(例如获取数据、延迟导入组件等)时抛出 Promise。这些 Promise 会在 Suspense 边界处被捕获。当渲染 Suspense 子树时抛出 Promise,React 会暂停渲染该子树,直到 Promise 被解析,然后才会再次尝试渲染。

RSC线格式

服务器输出的格式很简单,每行包含一个带有 ID 的 JSON 数据块。这种格式非常适合流式传输——客户端读取完一行后,就可以解析 JSON 片段并继续执行后续操作。

使用 RSC 格式

react-server-dom-webpack软件包包含接收 RSC 响应并重建 React 元素树的入口点。服务器完成数据加载后,会输出模块引用行(该引用定义了组件的模块引用)以及应该替换到引用所在位置的 React 元素树。

RSC 与从客户端组件获取数据

RSC 是否优于从客户端组件获取数据,取决于你要渲染到屏幕上的内容。使用 RSC,你可以获得非规范化的“处理后”数据,这些数据可以直接映射到你向用户显示的内容。如果渲染需要多次数据获取,且这些获取操作呈瀑布式顺序,那么最好在服务器端进行数据获取,因为服务器端的数据延迟要低得多,而不是在浏览器端。

RSC 和 SSR

使用 React 18,可以将 SSR 和 RSC 结合起来,因此可以在服务器端生成 HTML,然后在浏览器中使用 RSC 来加载该 HTML。

服务器端渲染(SSR)

服务器端渲染 (SSR) 是一种将 React 应用程序在服务器端渲染成静态 HTML 字符串,然后将其发送给客户端的技术。这可以通过允许在所有 JavaScript 加载和解析完成之前显示页面来提高性能和 SEO。



import express from 'express';
import React from 'react';
import ReactDOMServer from 'react-dom/server';
import App from './App';

const server = express();

server.get('/', (req, res) => {
  const appString = ReactDOMServer.renderToString(<App />);

  res.send(`
    <!DOCTYPE html>
    <html>
      <head>
        <title>My App</title>
      </head>
      <body>
        <div id="root">${appString}</div>
        <script src="/bundle.js"></script>
      </body>
    </html>
  `);
});

server.listen(8080);


Enter fullscreen mode Exit fullscreen mode

在这个例子中,App 组件在服务器端被渲染成一个字符串,然后该字符串被插入到 HTML 响应中。客户端随后将这个静态 HTML “加载”成一个完全交互式的 React 应用。

React 服务器组件 (RSC)

React 服务器组件 (RSC) 允许服务器和客户端协同工作来渲染 React 应用程序。一些组件在服务器端渲染,另一些则在客户端渲染。这可以通过减少发送到客户端的 JavaScript 代码量并允许服务器直接获取和渲染数据来提高性能。

以下是一个简单的RSC示例:



// Message.server.js

import {db} from './db.server';

function Message({id}) {
  const message = db.messages.get(id);
  return (
    <div>
      <h1>{message.title}</h1>
      <p>{message.body}</p>
    </div>
  );
}

export default Message;


Enter fullscreen mode Exit fullscreen mode


// App.client.js

import {useState} from 'react';
import Message from './Message.server';

function App() {
  const [selectedId, setSelectedId] = useState(1);
  return (
    <div>
      <button onClick={() => setSelectedId(selectedId + 1)}>
        Next
      </button>
      <Message id={selectedId} />
    </div>
  );
}

export default App;


Enter fullscreen mode Exit fullscreen mode

在这个例子中,消息服务器组件根据 id 属性检索并渲染一条消息。应用程序客户端组件维护一个状态(selectedId),并使用当前 id 渲染消息服务器组件。

实用建议

  • 了解服务器组件和客户端组件之间的区别:了解哪些组件由服务器渲染,哪些组件由客户端渲染,对于有效使用 RSC 至关重要。

  • 将 Suspense 与 RSC 结合使用: Suspense 允许你在 React 组件中处理 Promise,这对于 RSC 的功能至关重要。

  • 优化性能: RSC 可以显著提升页面加载速度并减小文件包大小。但是,务必衡量并监控这些指标,以确保获得预期效果。

  • 权衡利弊:虽然 RSC 提供了诸多优势,但也存在一些不足。例如,服务器组件无法使用状态或效果,这可能会限制它们在某些情况下的使用。

  • 在应用程序的非关键部分试用 RSC:鉴于 RSC 的实验性质,最好先在应用程序的非关键部分进行试用。这将有助于您更好地了解其工作原理以及如何有效地使用它。

  • 将 RSC 与其他 React 功能结合使用: RSC 可以与其他 React 功能(如 Suspense 和并发模式)结合使用,以构建更高效、更用户友好的应用程序。

例如。

让我们来看一些代码示例,以说明 React 服务器组件 (RSC) 的工作原理。

首先,我们来定义一个服务器组件。服务器组件通过 .server.js 扩展名来识别:



// Message.server.js

import {db} from './db.server';

function Message({id}) {
  const message = db.messages.get(id);
  return (
    <div>
      <h1>{message.title}</h1>
      <p>{message.body}</p>
    </div>
  );
}

export default Message;


Enter fullscreen mode Exit fullscreen mode

在这个例子中,Message 是一个服务器组件,它根据 id 属性从数据库中获取消息。请注意,我们直接导入了一个服务器模块 (db.server) 并使用它来获取数据。在客户端组件中是不能这样做的。

接下来,我们定义一个使用此服务器组件的客户端组件:



// App.client.js

import {useState} from 'react';
import Message from './Message.server';

function App() {
  const [selectedId, setSelectedId] = useState(1);
  return (
    <div>
      <button onClick={() => setSelectedId(selectedId + 1)}>
        Next
      </button>
      <Message id={selectedId} />
    </div>
  );
}

export default App;


Enter fullscreen mode Exit fullscreen mode

在这个例子中,App 是一个客户端组件,它维护着一个状态(selectedId),并使用当前 ID 渲染 Message 服务器组件。当点击“下一步”按钮时,selectedId 的值会递增,从而导致 Message 组件使用新的 ID 再次渲染。

这是一个简单的例子,但它说明了 RSC 背后的关键思想:服务器组件可用于在服务器上获取和渲染数据,而客户端组件则在客户端保持交互性。

比较

虽然 SSR 和 RSC 都涉及服务器端渲染,但它们的用途不同,优缺点也不同:

服务端渲染(SSR) 主要通过向客户端发送静态 HTML 来提升性能和 SEO。然而,它需要将所有 JavaScript 代码都发送到客户端,这会导致代码量庞大且解析速度缓慢。
另一方面,响应式渲染 (RSC) 允许服务器和客户端协同渲染,从而减少发送到客户端的 JavaScript 代码量并提升性能。但是,服务器组件无法使用状态或副作用,这可能会限制其在某些场景下的使用。
总而言之,SSR 和 RSC 都是强大的 React 应用渲染技术,各有优缺点。了解这些差异可以帮助您在项目中更明智地选择合适的技术。

相关链接:
https://react.dev/blog/2022/03/29/react-v18
https://react.dev/blog/2020/12/21/data-fetching-with-react-server-components
https://react.dev/blog/2023/03/22/react-labs-what-we-have-been-working-on-march-2023#react-server-components
https://shopify.github.io/hydrogen-v1/tutorials/react-server-components
https://www.plasmic.app/blog/how-react-server-components-work

文章来源:https://dev.to/xakrume/react-server-components-deep-dive-29af