跳到内容

10

服务器与客户端组件

要理解服务端和客户端组件的工作原理,熟悉两个基本的 Web 概念会很有帮助

  • 应用程序代码可以在其中执行的环境:服务端和客户端。
  • 将服务端和客户端代码分隔开的网络边界

服务端和客户端环境

在 Web 应用程序的上下文中

Diagram showing a browser on the left and a server on the right, separated by a network boundary.
  • 客户端指的是用户设备上的浏览器,它向服务器发送请求以获取应用程序代码。然后,它将从服务器接收到的响应转换为用户可以与之交互的界面。
  • 服务器指的是数据中心中的计算机,它存储您的应用程序代码,接收来自客户端的请求,进行一些计算,并发送回适当的响应。

每个环境都有其自身的特性和限制。例如,通过将渲染和数据获取移至服务器,您可以减少发送到客户端的代码量,这可以提高应用程序的性能。但是,正如您之前了解到的,要使您的 UI 具有交互性,您需要在客户端更新 DOM。

因此,您为服务器和客户端编写的代码并不总是相同的。某些操作(例如数据获取或管理用户状态)更适合其中一个环境。

网络边界

网络边界是一条概念性的线,它将不同的环境分隔开来。

在 React 中,您可以选择在组件树中放置网络边界的位置。例如,您可以在服务器上获取数据并渲染用户的帖子(使用服务端组件),然后为每个帖子在客户端渲染交互式的 LikeButton(使用客户端组件)。

同样,您可以创建一个在服务器上渲染并在页面之间共享的 Nav 组件,但如果您想显示链接的活动状态,则可以在客户端渲染 Links 列表。

A component tree showing a layout that has 3 components as its children: Nav, Page, and Footer. The page component has 2 children: Posts and LikeButton. The Posts component is rendered on the server, and the LikeButton component is rendered on the client.

在幕后,组件被拆分为两个模块图。服务端模块图(或树)包含所有在服务器上渲染的服务端组件,而客户端模块图(或树)包含所有客户端组件。

服务端组件渲染完成后,一种特殊的数据格式,称为 React 服务端组件 Payload (RSC),被发送到客户端。RSC payload 包含

  1. 服务端组件的渲染结果。
  2. 客户端组件应该渲染的占位符(或空洞)以及它们 JavaScript 文件的引用。

React 使用此信息来整合服务端和客户端组件并更新客户端上的 DOM。

让我们看看它是如何工作的。

使用客户端组件

正如您在上一章中了解到的,Next.js 默认使用服务端组件——这是为了提高应用程序的性能,这意味着您无需采取额外步骤即可采用它们。

回顾浏览器中的错误,Next.js 警告您正在尝试在服务端组件中使用 useState。您可以通过将交互式“点赞”按钮移至客户端组件来解决此问题。

app 文件夹中创建一个名为 like-button.js 的新文件,该文件导出 LikeButton 组件

/app/like-button.js
export default function LikeButton() {}

<button> 元素和 handleClick() 函数从 page.js 移动到新的 LikeButton 组件中

/app/like-button.js
export default function LikeButton() {
  function handleClick() {
    setLikes(likes + 1);
  }
 
  return <button onClick={handleClick}>Like ({likes})</button>;
}

接下来,移动 likes 状态和导入

/app/like-button.js
import { useState } from 'react';
 
export default function LikeButton() {
  const [likes, setLikes] = useState(0);
 
  function handleClick() {
    setLikes(likes + 1);
  }
 
  return <button onClick={handleClick}>Like ({likes})</button>;
}

现在,要使 LikeButton 成为客户端组件,请在文件顶部添加 React 'use client' 指令。这会告诉 React 在客户端渲染该组件。

/app/like-button.js
'use client';
 
import { useState } from 'react';
 
export default function LikeButton() {
  const [likes, setLikes] = useState(0);
 
  function handleClick() {
    setLikes(likes + 1);
  }
 
  return <button onClick={handleClick}>Like ({likes})</button>;
}

回到 page.js 文件中,将 LikeButton 组件导入到您的页面中

/app/page.js
import LikeButton from './like-button';
 
function Header({ title }) {
  return <h1>{title ? title : 'Default title'}</h1>;
}
 
export default function HomePage() {
  const names = ['Ada Lovelace', 'Grace Hopper', 'Margaret Hamilton'];
 
  return (
    <div>
      <Header title="Develop. Preview. Ship." />
      <ul>
        {names.map((name) => (
          <li key={name}>{name}</li>
        ))}
      </ul>
      <LikeButton />
    </div>
  );
}

保存这两个文件并在浏览器中查看您的应用程序。现在没有错误了,一旦您进行更改并保存,您应该会注意到浏览器会自动更新以反映更改。

此功能称为快速刷新。它为您所做的任何编辑提供即时反馈,并且预先配置在 Next.js 中。

总结

总结一下,您了解了服务端和客户端环境以及何时使用它们。您还了解到 Next.js 默认使用 React 服务端组件来提高性能,以及如何选择客户端组件来使 UI 的小部分具有交互性。

补充阅读

关于服务端和客户端组件还有很多需要学习的地方。以下是一些补充资源

您已完成本章10

您已经学会了如何使用服务端和客户端组件。

下一章

11: 下一步

下一步是什么?