Skip to main content

客户端组件

客户端组件允许你编写 在服务器上预渲染 的交互式 UI,并且可以使用客户端 JavaScript 在浏览器中运行。

¥Client Components allow you to write interactive UI that is prerendered on the server and can use client JavaScript to run in the browser.

本页将介绍客户端组件如何工作、如何渲染以及何时可以使用它们。

¥This page will go through how Client Components work, how they're rendered, and when you might use them.

客户端渲染的好处

¥Benefits of Client Rendering

在客户端上进行渲染工作有几个好处,包括:

¥There are a couple of benefits to doing the rendering work on the client, including:

  • 互动性:客户端组件可以使用状态、效果和事件监听器,这意味着它们可以向用户提供即时反馈并更新 UI。

    ¥Interactivity: Client Components can use state, effects, and event listeners, meaning they can provide immediate feedback to the user and update the UI.

  • 浏览器 API:客户端组件可以访问浏览器 API,例如 geolocationlocalStorage

    ¥Browser APIs: Client Components have access to browser APIs, like geolocation or localStorage.

在 Next.js 中使用客户端组件

¥Using Client Components in Next.js

要使用客户端组件,你可以将 React "use client" 指令 添加到文件顶部、导入上方。

¥To use Client Components, you can add the React "use client" directive at the top of a file, above your imports.

"use client" 用于声明服务器和客户端组件模块之间的 boundary。这意味着通过在文件中定义 "use client",导入到其中的所有其他模块(包括子组件)都被视为客户端打包包的一部分。

¥"use client" is used to declare a boundary between a Server and Client Component modules. This means that by defining a "use client" in a file, all other modules imported into it, including child components, are considered part of the client bundle.

'use client'

import { useState } from 'react'

export default function Counter() {
const [count, setCount] = useState(0)

return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>Click me</button>
</div>
)
}
'use client'

import { useState } from 'react'

export default function Counter() {
const [count, setCount] = useState(0)

return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>Click me</button>
</div>
)
}

下图显示,如果未定义 "use client" 指令,在嵌套组件 (toggle.js) 中使用 onClickuseState 将导致错误。这是因为,默认情况下,App Router 中的所有组件都是这些 API 不可用的服务器组件。通过在 toggle.js 中定义 "use client" 指令,你可以告诉 React 进入这些 API 可用的客户端边界。

¥The diagram below shows that using onClick and useState in a nested component (toggle.js) will cause an error if the "use client" directive is not defined. This is because, by default, all components in the App Router are Server Components where these APIs are not available. By defining the "use client" directive in toggle.js, you can tell React to enter the client boundary where these APIs are available.

定义多个 use client 入口点:

¥Defining multiple use client entry points:

你可以在 React 组件树中定义多个 "使用客户端" 入口点。这允许你将应用拆分为多个客户端包。

¥You can define multiple "use client" entry points in your React Component tree. This allows you to split your application into multiple client bundles.

但是,不需要在每个需要在客户端渲染的组件中定义 "use client"。定义边界后,导入其中的所有子组件和模块都将被视为客户端打包包的一部分。

¥However, "use client" doesn't need to be defined in every component that needs to be rendered on the client. Once you define the boundary, all child components and modules imported into it are considered part of the client bundle.

客户端组件是如何渲染的?

¥How are Client Components Rendered?

在 Next.js 中,客户端组件的渲染方式有所不同,具体取决于请求是完整页面加载(对应用的初始访问还是浏览器刷新触发的页面重新加载)或后续导航的一部分。

¥In Next.js, Client Components are rendered differently depending on whether the request is part of a full page load (an initial visit to your application or a page reload triggered by a browser refresh) or a subsequent navigation.

整页加载

¥Full page load

为了优化初始页面加载,Next.js 将使用 React 的 API 在服务器上为客户端和服务器组件渲染静态 HTML 预览。这意味着,当用户第一次访问你的应用时,他们将立即看到页面的内容,而无需等待客户端下载、解析和执行客户端组件 JavaScript 包。

¥To optimize the initial page load, Next.js will use React's APIs to render a static HTML preview on the server for both Client and Server Components. This means, when the user first visits your application, they will see the content of the page immediately, without having to wait for the client to download, parse, and execute the Client Component JavaScript bundle.

在服务器上:

¥On the server:

  1. React 将服务器组件渲染为一种称为 React 服务器组件有效负载(RSC 有效负载) 的特殊数据格式,其中包括对客户端组件的引用。

    ¥React renders Server Components into a special data format called the React Server Component Payload (RSC Payload), which includes references to Client Components.

  2. Next.js 使用 RSC 有效负载和客户端组件 JavaScript 指令在服务器上渲染路由的 HTML。

    ¥Next.js uses the RSC Payload and Client Component JavaScript instructions to render HTML for the route on the server.

然后,在客户端:

¥Then, on the client:

  1. HTML 用于立即显示路由的快速非交互式初始预览。

    ¥The HTML is used to immediately show a fast non-interactive initial preview of the route.

  2. React 服务器组件有效负载用于协调客户端和服务器组件树,并更新 DOM。

    ¥The React Server Components Payload is used to reconcile the Client and Server Component trees, and update the DOM.

  3. JavaScript 指令用于 hydrate 客户端组件并使其 UI 具有交互性。

    ¥The JavaScript instructions are used to hydrate Client Components and make their UI interactive.

什么是保湿?

¥What is hydration?

Hydration 是将事件监听器附加到 DOM 的过程,以使静态 HTML 具有交互性。在幕后,水合作用是通过 hydrateRoot React API 完成的。

¥Hydration is the process of attaching event listeners to the DOM, to make the static HTML interactive. Behind the scenes, hydration is done with the hydrateRoot React API.

后续导航

¥Subsequent Navigations

在后续导航中,客户端组件完全在客户端上渲染,而不需要服务器渲染的 HTML。

¥On subsequent navigations, Client Components are rendered entirely on the client, without the server-rendered HTML.

这意味着客户端组件 JavaScript 包已下载并解析。一旦包准备好,React 将使用 RSC 有效负载 来协调客户端和服务器组件树,并更新 DOM。

¥This means the Client Component JavaScript bundle is downloaded and parsed. Once the bundle is ready, React will use the RSC Payload to reconcile the Client and Server Component trees, and update the DOM.

回到服务器环境

¥Going back to the Server Environment

有时,在声明 "use client" 边界后,你可能想返回到服务器环境。例如,你可能希望减少客户端包大小、在服务器上获取数据或使用仅在服务器上可用的 API。

¥Sometimes, after you've declared the "use client" boundary, you may want to go back to the server environment. For example, you may want to reduce the client bundle size, fetch data on the server, or use an API that is only available on the server.

你可以将代码保留在服务器上,即使理论上代码是通过交错客户端和服务器组件以及 服务器操作 嵌套在客户端组件内的。请参阅 构图模式 页了解更多信息。

¥You can keep code on the server even though it's theoretically nested inside Client Components by interleaving Client and Server Components and Server Actions. See the Composition Patterns page for more information.