客户端组件 (Client Components)
客户端组件 (Client Components) 允许您编写可在请求时在客户端渲染的交互式 UI。在 Next.js 中,客户端渲染是可选的,这意味着您需要明确决定哪些组件应由 React 在客户端渲染。
本页将介绍客户端组件 (Client Components) 的工作原理、渲染方式以及适用场景。
客户端渲染的优势
在客户端执行渲染工作具有以下优势:
- 交互性:客户端组件 (Client Components) 可以使用状态 (state)、副作用 (effects) 和事件监听器 (event listeners),这意味着它们能即时响应用户操作并更新 UI。
- 浏览器 API:客户端组件 (Client Components) 能够访问浏览器 API,例如 地理位置 API 或 localStorage,从而支持构建特定场景的 UI。
在 Next.js 中使用客户端组件 (Client Components)
要使用客户端组件 (Client Components),您可以在文件顶部(导入语句之前)添加 React 的 "use client"
指令。
"use client"
用于声明服务端组件 (Server Components) 和客户端组件 (Client Components) 模块之间的边界。这意味着在文件中定义 "use client"
后,所有导入该文件的模块(包括子组件)都将被视为客户端包的一部分。
下图展示了嵌套组件的情况——如果在 toggle.js
中使用 onClick
和 useState
但未定义 "use client"
指令会导致错误。这是因为默认情况下组件会在服务端渲染,而这些 API 在服务端不可用。通过在 toggle.js
中定义 "use client"
指令,您可以告知 React 在客户端渲染该组件及其子组件,因为相关 API 在客户端可用。

定义多个
use client
入口点:您可以在 React 组件树中定义多个 "use client" 入口点。这允许将应用拆分为多个客户端包(或分支)。
但并非每个需要在客户端渲染的组件都必须定义
"use client"
。一旦定义边界后,所有子组件和导入的模块都将被视为客户端包的一部分。
客户端组件 (Client Components) 如何渲染?
在 Next.js 中,客户端组件 (Client Components) 的渲染方式取决于请求类型:完整页面加载(首次访问应用或浏览器刷新触发的页面重载)还是后续导航。
完整页面加载
为优化初始页面加载,Next.js 会使用 React 的 API 在服务端为客户端组件 (Client Components) 和服务端组件 (Server Components) 渲染静态 HTML 预览。这意味着用户首次访问应用时,可以立即看到页面内容,而无需等待客户端下载、解析和执行客户端组件 (Client Components) 的 JavaScript 包。
在服务端:
- React 将服务端组件 (Server Components) 渲染为特殊数据格式——React 服务端组件负载 (RSC Payload),其中包含对客户端组件 (Client Components) 的引用。
- Next.js 使用 RSC Payload 和客户端组件 (Client Components) 的 JavaScript 指令在服务端渲染路由的 HTML。
然后在客户端:
- 使用 HTML 立即显示路由的非交互式快速初始预览。
- 使用 React 服务端组件负载 (RSC Payload) 协调客户端组件 (Client Components) 和服务端组件 (Server Components) 的组件树,并更新 DOM。
- 使用 JavaScript 指令对客户端组件 (Client Components) 进行水合 (hydrate),使其 UI 具备交互性。
什么是水合 (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) 中,您仍可以通过交叉使用客户端组件 (Client Components)、服务端组件 (Server Components) 和服务端操作 (Server Actions) 将代码保留在服务端。更多信息请参阅组合模式页面。