客户端组件 (Client Components)

客户端组件 (Client Components) 允许您编写交互式用户界面,这些界面会在服务端预渲染,并能在浏览器中使用客户端 JavaScript 运行。

本页将介绍客户端组件 (Client Components) 的工作原理、渲染方式以及适用场景。

客户端渲染的优势

在客户端执行渲染工作具有以下优势:

  • 交互性:客户端组件 (Client Components) 可以使用状态 (state)、副作用 (effects) 和事件监听器 (event listeners),意味着它们能立即响应用户操作并更新界面。
  • 浏览器 API:客户端组件 (Client Components) 能够访问浏览器 API,例如地理位置定位本地存储

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

要使用客户端组件 (Client Components),您可以在文件顶部、导入语句之前添加 React 的 "use client" 指令

"use client" 用于声明服务端组件 (Server Components) 和客户端组件 (Client Components) 模块之间的边界。这意味着通过在文件中定义 "use client",所有导入该文件的模块(包括子组件)都将被视为客户端包的一部分。

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

下图展示了在嵌套组件 (toggle.js) 中使用 onClickuseState 时,如果未定义 "use client" 指令会导致错误。这是因为在应用路由 (App Router) 中,默认所有组件都是服务端组件 (Server Components),这些 API 不可用。通过在 toggle.js 中定义 "use client" 指令,您可以告知 React 进入这些 API 可用的客户端边界。

Use Client Directive and Network Boundary

定义多个 use client 入口点

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

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

客户端组件如何渲染?

在 Next.js 中,客户端组件 (Client Components) 的渲染方式取决于请求是完整页面加载(首次访问应用或浏览器刷新触发的页面重载)还是后续导航。

完整页面加载

为了优化初始页面加载,Next.js 会使用 React 的 API 在服务端为客户端组件 (Client Components) 和服务端组件 (Server Components) 渲染静态 HTML 预览。这意味着用户首次访问您的应用时,会立即看到页面内容,而无需等待客户端下载、解析和执行客户端组件 (Client Components) 的 JavaScript 包。

在服务端:

  1. React 将服务端组件 (Server Components) 渲染为一种特殊数据格式——React 服务端组件负载 (RSC Payload),其中包含对客户端组件 (Client Components) 的引用。
  2. Next.js 使用 RSC Payload 和客户端组件 (Client Components) 的 JavaScript 指令在服务端渲染路由的 HTML

然后在客户端:

  1. 使用 HTML 立即显示路由的快速非交互式初始预览。
  2. 使用 React 服务端组件负载 (RSC Payload) 协调客户端组件 (Client Components) 和服务端组件 (Server Components) 的组件树,并更新 DOM。
  3. 使用 JavaScript 指令对客户端组件 (Client Components) 进行水合 (hydrate),使其界面可交互。

什么是水合 (hydration)?

水合 (hydration) 是将事件监听器附加到 DOM 的过程,使静态 HTML 具有交互性。在底层,水合是通过 React 的 hydrateRoot API 实现的。

后续导航

在后续导航中,客户端组件 (Client Components) 完全在客户端渲染,不使用服务端渲染的 HTML。

这意味着客户端组件 (Client Components) 的 JavaScript 包会被下载并解析。一旦包准备就绪,React 将使用 RSC Payload 协调客户端组件 (Client Components) 和服务端组件 (Server Components) 的组件树,并更新 DOM。

返回服务端环境

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

您可以通过交错使用客户端组件 (Client Components) 和服务端组件 (Server Components) 以及服务端操作 (Server Actions),将代码保留在服务端,即使它们在理论上嵌套在客户端组件 (Client Components) 内部。更多信息请参阅组合模式页面。

On this page