logo
Published on

React Server Components 服务端组件

Authors

React Server Components

2020 年 12 月 21 日,React 官方发布了 React Server Components 的介绍文章,并配上了由 Dan Abramov 和 Lauren Tan 两位 React 团队的工程师分享的长约 1h 的分享Demo,详细的介绍了 React Server Components 的出现背景和使用方式。

使用 React Server Component,因为服务端组件的代码不会打包到客户端代码中,它可以减小包(bundle)的大小。且在 React Server Component 中,可以直接访问后端资源。当然因为在服务端运行,对应也有一些限制,比如不能使用 useEffect 和客户端事件等。

Server-side Rendering

Server-side Rendering,中文译为“服务端渲染”,在上篇《渲染篇 | 从 CSR、SSR、SSG、ISR 开始说起》已经介绍过,并提供了一个基于 Pages Router 的 demo:

// pages/ssr.js
export default function Page({ data }) {
  return <p>{JSON.stringify(data)}</p>;
}

export async function getServerSideProps() {
  const res = await fetch(`https://jsonplaceholder.typicode.com/todos`);
  const data = await res.json();

  return { props: { data } };
}

从这个例子中可以看出,Next.js v12 之前的 SSR 都是通过 getServerSideProps这样的方法,在页面层级获取数据,然后通过 props 传给每个组件,然后将整个组件树在服务端渲染为 HTML。

但是 HTML 是没有交互性的(non-interactive UI),客户端渲染出 HTML 后,还要等待 JavaScript 完全下载并执行。JavaScript 会赋予 HTML 交互性,这个阶段被称为水合(Hydration)。此时内容变为可交互的(interactive UI)。

从这个过程中,我们可以看出 SSR 的几个缺点:

  1. SSR 的数据获取必须在组件渲染之前
  2. 组件的 JavaScript 必须先加载到客户端,才能开始水合
  3. 所有组件必须先水合,然后才能跟其中任意一个组件交互

可以看出 SSR 这种技术“大开大合”,加载整个页面的数据,加载整个页面的 JavaScript,水合整个页面,还必须按此顺序串行执行。如果有某些部分慢了,都会导致整体效率降低。

此外,SSR 只用于页面的初始化加载,对于后续的交互、页面更新、数据更改,SSR 并无作用。

RSC 与 SSR

了解了这两个基本概念,现在让我们来回顾下 React Server Components 和 Server-side Rendering,表面上看,RSC 和 SSR 非常相似,都发生在服务端,都涉及到渲染,目的都是更快的呈现内容。但实际上,这两个技术概念是相互独立的。RSC 和 SSR 既可以各自单独使用,又可以搭配在一起使用(搭配在一起使用的时候是互补的)。

正如它们的名字所表明的那样,Server-side Rendering 的重点在于 Rendering,React Server Components 的重点在于 Components

简单来说,RSC 提供了更细粒度的组件渲染方式,可以在组件中直接获取数据,而非像 Next.js v12 中的 SSR 顶层获取数据。RSC 在服务端进行渲染,组件依赖的代码不会打包到 bundle 中,而 SSR 需要将组件的所有依赖都打包到 bundle 中。

当然两者最大的区别是:

SSR 是在服务端将组件渲染成 HTML 发送给客户端,而 RSC 是将组件渲染成一种特殊的格式,我们称之为 RSC Payload。这个 RSC Payload 的渲染是在服务端,但不会一开始就返回给客户端,而是在客户端请求相关组件的时候才返回给客户端,RSC Payload 会包含组件渲染后的数据和样式,客户端收到 RSC Payload 后会重建 React 树,修改页面 DOM。

注意:这里我们比较的是 React Demo 展示的 RSC 特性和 Next.js v12 所代表的传统 SSR。跟我们接下来要讲的 Next.js 服务端组件、客户端组件并不一样。

Next.js 的服务端组件、客户端组件虽然是基于 RSC 提出的用于区分组件类型的概念,但在具体实现上,为了追求高性能,技术上其实是融合了 RSC 和 SSR(前面也说过,RSC 和 SSR 互补)。这里比较是纯粹的 RSC 和 SSR,以防大家在概念理解上产生混淆。

总结

本篇我们介绍并比较了 RSC 和 SSR,虽然并不涉及 Next.js 具体的写法和使用,但对于大家理解 Next.js 中的服务端组件、客户端组件概念有所帮助。