yliu

时来天地皆同力,运去英雄不自由

React RSC


React RSC

最近 React 19 已经属于测试版本了,里面更新了很多功能,其中就包含今天要说的 RSC。你可能在某个框架(如 Next.js 或 Remix)中已经使用过了对它有了一定的理解,但不确定它的使用方式,或者你很想知道它到底是什么。

在本文中,主要是分享 React 服务器组件(RSC)的出现的目的、动机和缺点,了解它的工作原理,并希望建立一个思考 React 服务器组件的心理模型。

不过这里需要注意,RSC 跟 SSR(服务器端渲染)不是一个概念不要与 RSC 混淆。

用一个搭建积木的例子来解释,假设你有一个装满乐高积木的盒子,最终你会想要玩这些积木,并且必须打开盒子,将它们全部拿出来并设置好,然后才能开始玩。这就是默认 React 应用的工作原理。在准备好使用之前,有一个初始加载时间。

而有了 RSC,你的盒子里有一个特殊的工具,可以将这些部件组合在一起,然后你就可以开始玩了。你无需从头开始设置部件(客户端),而是有一个工具(服务器),可以将部件设置成随时可用的部分,你只需将它们放到最终位置即可。

传统的 SSR 存在于早期的网站中,使用像 PHP 这样的服务器端语言,根据需求从服务器发送整个网页,有诸如 SEO、减少客户端加载时间等优点。但是 SSR 的一个缺点是在 hydration 之后,与应用程序的后续交互需要对动态组件进行额外的调用。

接下来,将分享 RSC 背后的动机以及解决的功能和痛点。

动机

React 团队于 2020 年 12 月首次公布了 RSC(React Server Components)的 RFC,并在前不久进行了公测。

性能和速度

服务器组件提供了“开箱即用”的良好性能,这是常规 React 应用程序的主要痛点之一。它以不同的方式实现这一点:

它允许在服务器上使用第三方软件包,这可以显著减少应用程序的包大小。例如,如果只在特定的服务器组件中需要,那么可以简单地删除最常用的软件包,如日期库 (date-fns)、实用工具库 (lodash) 等。

// 客户端组件

import lodash from "lodash"; // 71.5 (25.3k gzipped)

function TableComponent({ text }) {
  // 使用一些lodash函数
  return /_ render _/;
}
// 使用服务器组件,但是不会在客户使用 lodash

import lodash from "lodash";

function TableComponent({ text }) {
  // 使用一些lodash函数
  return /_ render _/;
}

这对用户来说非常有益,并且为开发人员提供了更好的开发体验(DX)。

共享服务器-客户端 上下文

这可能是 RSC 最具影响力和有用的功能。使用 React 开发时经常需要跟后端进行数据的请求来渲染页面。所以早期的 React 一直以客户端为中心,开发人员在为客户端和服务器编写代码时经常使用不同的语言,通常是 PHP/Python 和 JS。后端代码主要负责访问文件系统、数据库和外部数据源。

然而,RSC 明确地重新定义了这种方法,消除了对 API request-response。通过让 React 访问后端,客户端和服务器之间的边界得到了简化,默认模式下允许数据库调用、文件系统访问以及将 props 直接传递给组件。

以下是是服务器组件的一些例子:

文件系统

import fs from "fs";

async function Post({ slug }) {
  const post = JSON.parse(await fs.readFile(`${slug}.md`));
  return <PostComponent post={post} />;
}

数据库调用

import db from "db";

async function Post({ slug }) {
  const post = await db.findOne(slug);
  return <PostComponent post={post} />;
}

使用服务器组件,避免发送密钥(例如用户令牌和 API 密钥)的安全优势也非常显著,因为客户端可以访问其他必要数据,而无需向客户端公开关键数据。

开发人员体验

在客户端组件中定义了类型化的 props,并接受来自服务器组件的数据。这种方法可以提供更好的开发人员体验,并在客户端和服务器上提供完全类型的体验。

首先,使用 use client 将组件变为客户端组件:

"use client";

export default function Author({ authorName }: { authorName: string }) {
  return <div className="text-xl font-bold">{authorName}</div>;
}

然后在服务器组件中调用:

import db from "db";

async function Post({ id }) {
  const author = await db.findOne(id);
  return (
    <Author
      authorName={author.name} // 会在类型不匹配时显示错误
    />
  );
}

缺点

RSC 也有一些缺点:

学习负担

在使用新功能时可能会导致使用 React 生态遇到一些问题,以及引入新思维需要额外的学习成本。此外 RSC 允许你直接跟文件、数据库等进行交互,需要额外了解后端开发的一些知识。

落地需要沉淀

目前还是公测版本,API 可能还会进行改变,更重要是有一个落地的框架可以直接让开发者使用。

最后

RSC 提供了一种新的编程方式,可以根据自身的业务场景选择。但是随着 AI 的发展说不定有一天可以让其代替根据用户信息的不同,返回不同的内容。

参考链接