最近 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) 等。
js
// 客户端组件
import lodash from "lodash"; // 71.5 (25.3k gzipped)
function TableComponent({ text }) {
// 使用一些lodash函数
return /_ render _/;
}
js
// 使用服务器组件,但是不会在客户使用 lodash
import lodash from "lodash";
function TableComponent({ text }) {
// 使用一些lodash函数
return /_ render _/;
}
这对用户来说非常有益,并且为开发人员提供了更好的开发体验(DX)。
共享服务器-客户端 上下文
这可能是 RSC 最具影响力和有用的功能。使用 React 开发时经常需要跟后端进行数据的请求来渲染页面。所以早期的 React 一直以客户端为中心,开发人员在为客户端和服务器编写代码时经常使用不同的语言,通常是 PHP/Python 和 JS。后端代码主要负责访问文件系统、数据库和外部数据源。
然而,RSC 明确地重新定义了这种方法,消除了对 API request-response。通过让 React 访问后端,客户端和服务器之间的边界得到了简化,默认模式下允许数据库调用、文件系统访问以及将 props 直接传递给组件。
以下是是服务器组件的一些例子:
文件系统
js
import fs from "fs";
async function Post({ slug }) {
const post = JSON.parse(await fs.readFile(`${slug}.md`));
return <PostComponent post={post} />;
}
数据库调用
js
import db from "db";
async function Post({ slug }) {
const post = await db.findOne(slug);
return <PostComponent post={post} />;
}
使用服务器组件,避免发送密钥(例如用户令牌和 API 密钥)的安全优势也非常显著,因为客户端可以访问其他必要数据,而无需向客户端公开关键数据。
开发人员体验
在客户端组件中定义了类型化的 props,并接受来自服务器组件的数据。这种方法可以提供更好的开发人员体验,并在客户端和服务器上提供完全类型的体验。
首先,使用 use client
将组件变为客户端组件:
js
"use client";
export default function Author({ authorName }: { authorName: string }) {
return <div className="text-xl font-bold">{authorName}</div>;
}
然后在服务器组件中调用:
js
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 的发展说不定有一天可以让其代替根据用户信息的不同,返回不同的内容。