React Server Components 2023 学习参考指南
React Server Components 是 React 团队推出的一种新型组件。它们提供了服务器端和客户端渲染的无缝结合,允许开发人员在服务器上渲染部分应用程序,同时保持客户端应用程序的交互性。
首先我们需要知道什么是Client Component 和 Server Components。
什么是 Client Component
客户端组件是在客户端上运行的组件,通常在web浏览器中。该组件可以访问DOM(文档对象模型)、浏览器api、事件等,而服务器无法访问这些组件。他们负责处理用户交互和更新用户界面。
什么是 Server Components
服务器组件是在服务器上获取和渲染的组件。它们与传统的React组件类似,但在服务器而不是客户端上执行。这意味着它们可以访问服务器的全部功能,并且可以执行在客户机上无法执行的任务,例如数据库查询。
可以把 Server Components 看作是后端。
为什么需要 Server Components
当我们使用客户端组件时,浏览器必须安装所有依赖的包才能构建网站,这可能会导致加载时间过长,影响网站的效率,用户体验差。
使用 Server Components 时,浏览器只需要下载客户端组件所需的JavaScript,而不是整个网站的js。
server components 优点
- 服务端组件不会出现在客户端的bundle中,所以浏览器只会下载客户端所需要的js。
- 自动代码分割,加载必要的客户端代码。
什么时候使用服务端组件和客户端组件
使用服务端组件情况
- 你需要请求数据或者减少客户端渲染bundle的大小。
- 想要减少页面的加载时间。
- 想要基于数据库或文件系统的操作等,任何没有交互性或生命周期钩子的组件。
使用客户端组件的情况
- 使用与浏览器相关的东西,比如按钮、点击事件、窗口、浏览器api等。
- 使用生命周期事件、useState、useEffect等。
体验Server Components
我们可以在next.js 13中开始体验使用服务器组件。在 Next.js 13 中,默认情况下每个组件都是一个Server组件,不需要使用use server 显示的声明。
安装 nextjs
npx create-next-app@latest
创建客户端组件
让我们将这个客户端组件命名为Card,并创建一个名为components的新目录,这样您的文件将是components/ Card.client.js。任何未来的组件,都可以存在于组件中。
card组件参考图:

因为Card组件有一个按钮,也就是说,它将有onClick事件,所以它是一个客户端组件。要将Card声明为Client组件,我们需要在页面顶部添加一个use client指令。这意味着Card将包含在客户端JavaScript包中,而不会在服务器上渲染。
'use client';
export default function Card({title, content}) {
const handleClick = () => {
}
return (
<div>
<div>{title}</div>
<div>{content}</div>
<div>
<button onClick={handleClick}>按钮</button>
</div>
</div>
)
}
建议:
从组件命名上区分客户端和服务器组件,例如,我们将card重命名为 card.client.jsx,因为它是客户端组件,而对于服务器,我们可以将其命名为:组件名字.server.jsx。
在服务器组件Page中调用Card不会使Page成为客户端组件,但是如果您要在客户端组件中调用Server,那么它将被包含在客户端bundle中,从而使其成为客户端组件。
使用Chrome浏览器,打开开发者工具,然后打开Sources面板。展开webpack-internal://,并找到(app-client) components。components目录显示了应用中的组件。
注意,Card位于组件内部的JavaScript bundle中。这意味着它是一个客户端组件。如果Card是一个Server组件,就不会出现在bundle。
服务端组件 VS 服务端渲染
服务器端渲染是一种从服务器获取数据的方法,与服务器组件是互补的。
在服务器端渲染中,当浏览器等客户端从服务器请求数据时,在初始加载时从服务器上获取数据。服务器将向客户端返回HTML。然后客户端必须等待JavaScript下载,以便网站可以交互。
服务端组件不是返回HTML,而是返回渲染UI描述的对象。使React在不丢失状态的情况下将数据与现有的客户端组件合并。
UI的描述是一种新的中间格式。它不是JSON,但看起来像JSON。中间状态: M1:{"id":"./app/page.js","chunks":["client"],"name":""}
服务器组件与SSR不同:
- 服务器组件代码永远不会发送到客户端。相比之下,对于传统的 SSR,所有组件代码都以 JS bundle 的形式发送到客户端。
- 服务器组件让您可以直接访问后端。
- 可以在不丢失树中的客户端状态的情况下重新获取服务器组件。这是因为传输的是比HTML更丰富的中间状态,我们可以重新获取服务器渲染的部分(例如搜索结果列表),而不需要删除内部的状态(例如搜索输入文本、焦点和选择)。
共享组件
共享组件是既可以在 Server 渲染,又可以在 Client 渲染。命名方式为组件以.js 结尾,而不是.server.js 或.client.js
如果 Server Component 里用到了 Shared Component 或 Server Component,那么将会在 Server 渲染后,以指令的形式返回给 Client,他们不会被下载到 Client。如果 Client Component 里用到了 Shared Component 或 Client Component,那么会在浏览器渲染,他们会被下载到 Client。
如果我们有一个日期字段需要进行不同的格式化,于是我们封装成一个组件,使用date-fns格式化时间。 让我们通过运行npm install date-fns来安装date-fns。创建一个新文件components/date.js。
import { parseISO, format } from 'date-fns';
export default function DisplayDate({
dateString,
formatType = 'LLLL dd, yyyy',
}) {
const date = parseISO(dateString);
return <time dateTime={dateString}>{format(date, formatType)}</time>;
}
在例子中,当我们在Card组件中使用了DisplayDate组件,它将成为一个客户端组件,因为Card是一个客户端组件。
'use client';
import DisplayDate from "./date";
export default function Card({title, content, date}) {
const handleClick = () => {
}
return (
<div>
<div>{title}</div>
<div>{content}</div>
<DisplayDate dateString={date} />
<div>
<button onClick={handleClick}>按钮</button>
</div>
</div>
)
}
我们打开Chrome浏览器。打开开发者工具,然后打开Sources面板。转到webpack-internal://并找到组件。components目录显示了应用中的组件。
如果从Card中移除DisplayDate组件并且只在Page中调用它,那么将不会在客户端bundle中看到DisplayDate组件。
page.js:
import Card from '../components/card.client'
import DisplayDate from '@/components/date';
const getData = () => {
return [
{
id: 1,
title: "我是个标题1",
content: "Server Components1",
formattedDate: '2023-01-10'
},
{
id: 2,
title: "我是个标题2",
content: "Server Components2",
formattedDate: '2023-01-10'
}
]
}
export default function Home() {
const data = getData();
return (
<main className="flex min-h-screen flex-col items-center justify-between p-24">
{
data.map(({id, title, content, formattedDate}) => (
<div key={id}>
<Card
title={title}
content={content}
date={formattedDate}
/>
</div>
))
}
<DisplayDate dateString={'2023-01-10'} />
</main>
)
}
可以看到date.js组件没有出现在js bundle中,引用的date-fns也没有出现在包中。
总结
服务器组件是在服务器上获取和渲染的组件。它们与传统的React组件类似,但在服务器端进行的而不是客户端上执行。
转载自:https://juejin.cn/post/7233220422240878647