天天看点

React Server Components 2023 学习参考指南

作者:Java热点

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 优点

  1. 服务端组件不会出现在客户端的bundle中,所以浏览器只会下载客户端所需要的js。
  2. 自动代码分割,加载必要的客户端代码。

什么时候使用服务端组件和客户端组件

使用服务端组件情况

  1. 你需要请求数据或者减少客户端渲染bundle的大小。
  2. 想要减少页面的加载时间。
  3. 想要基于数据库或文件系统的操作等,任何没有交互性或生命周期钩子的组件。

使用客户端组件的情况

  1. 使用与浏览器相关的东西,比如按钮、点击事件、窗口、浏览器api等。
  2. 使用生命周期事件、useState、useEffect等。

体验Server Components

我们可以在next.js 13中开始体验使用服务器组件。在 Next.js 13 中,默认情况下每个组件都是一个Server组件,不需要使用use server 显示的声明。

安装 nextjs

js复制代码npx create-next-app@latest
           

创建客户端组件

让我们将这个客户端组件命名为Card,并创建一个名为components的新目录,这样您的文件将是components/ Card.client.js。任何未来的组件,都可以存在于组件中。

card组件参考图:

React Server Components 2023 学习参考指南

因为Card组件有一个按钮,也就是说,它将有onClick事件,所以它是一个客户端组件。要将Card声明为Client组件,我们需要在页面顶部添加一个use client指令。这意味着Card将包含在客户端JavaScript包中,而不会在服务器上渲染。

js复制代码'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。
React Server Components 2023 学习参考指南

服务端组件 VS 服务端渲染

服务器端渲染是一种从服务器获取数据的方法,与服务器组件是互补的。

在服务器端渲染中,当浏览器等客户端从服务器请求数据时,在初始加载时从服务器上获取数据。服务器将向客户端返回HTML。然后客户端必须等待JavaScript下载,以便网站可以交互。

服务端组件不是返回HTML,而是返回渲染UI描述的对象。使React在不丢失状态的情况下将数据与现有的客户端组件合并。

UI的描述是一种新的中间格式。它不是JSON,但看起来像JSON。中间状态: M1:{"id":"./app/page.js","chunks":["client"],"name":""}

服务器组件与SSR不同:

  1. 服务器组件代码永远不会发送到客户端。相比之下,对于传统的 SSR,所有组件代码都以 JS bundle 的形式发送到客户端。
  2. 服务器组件让您可以直接访问后端。
  3. 可以在不丢失树中的客户端状态的情况下重新获取服务器组件。这是因为传输的是比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。

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是一个客户端组件。

js复制代码'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目录显示了应用中的组件。

React Server Components 2023 学习参考指南

如果从Card中移除DisplayDate组件并且只在Page中调用它,那么将不会在客户端bundle中看到DisplayDate组件。

page.js:

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>
    )
}

           
React Server Components 2023 学习参考指南

可以看到date.js组件没有出现在js bundle中,引用的date-fns也没有出现在包中。

总结

服务器组件是在服务器上获取和渲染的组件。它们与传统的React组件类似,但在服务器端进行的而不是客户端上执行。

继续阅读