外观
客户端组件
客户端组件
客户端组件允许你编写交互式 UI,这些 UI 在服务器上预渲染,并可以使用客户端 JavaScript 在浏览器中运行。
本页将介绍客户端组件的工作原理、渲染方式以及何时使用它们。
客户端渲染的优势
在客户端进行渲染工作有几个好处,包括:
- 交互性: 客户端组件可以使用状态、效果和事件监听器,这意味着它们可以为用户提供即时反馈并更新 UI。
- 浏览器 API: 客户端组件可以访问浏览器 API,如地理位置或localStorage。
在 Next.js 中使用客户端组件
要使用客户端组件,你可以在文件顶部、导入语句之上添加 React 的 "use client"
指令。
"use client"
用于声明服务器和客户端组件模块之间的边界。这意味着通过在文件中定义 "use client"
,所有导入到该文件中的其他模块(包括子组件)都被视为客户端包的一部分。
app/counter.tsx
'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>
)
}
app/counter.js
'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
)中使用 onClick
和 useState
将导致错误。这是因为默认情况下,App Router 中的所有组件都是服务器组件,这些 API 在服务器组件中不可用。通过在 toggle.js
中定义 "use client"
指令,你可以告诉 React 进入客户端边界,在那里这些 API 是可用的。
提示
定义多个 use client
入口点:
你可以在 React 组件树中定义多个 "use client" 入口点。这允许你将应用程序拆分为多个客户端包。
然而,"use client"
不需要在每个需要在客户端渲染的组件中定义。一旦你定义了边界,所有导入到其中的子组件和模块都被视为客户端包的一部分。
客户端组件是如何渲染的?
在 Next.js 中,客户端组件的渲染方式取决于请求是完整页面加载(首次访问应用程序或由浏览器刷新触发的页面重新加载)还是后续导航。
完整页面加载
为了优化初始页面加载,Next.js 将使用 React 的 API 在服务器上为客户端和服务器组件渲染静态 HTML 预览。这意味着,当用户首次访问你的应用程序时,他们将立即看到页面内容,而无需等待客户端下载、解析和执行客户端组件的 JavaScript 包。
在服务器上:
- React 将服务器组件渲染成一种特殊的数据格式,称为 React 服务器组件有效负载(RSC Payload),其中包含对客户端组件的引用。
- Next.js 使用 RSC Payload 和客户端组件 JavaScript 指令在服务器上为路由渲染 HTML。
然后,在客户端:
- HTML 用于立即显示路由的快速非交互式初始预览。
- React 服务器组件有效负载用于协调客户端和服务器组件树,并更新 DOM。
- JavaScript 指令用于水合客户端组件并使其 UI 具有交互性。
后续导航
在后续导航中,客户端组件完全在客户端渲染,不需要服务器渲染的 HTML。
这意味着客户端组件的 JavaScript 包被下载和解析。一旦包准备就绪,React 将使用 RSC Payload 协调客户端和服务器组件树,并更新 DOM。
回到服务器环境
有时,在声明 "use client"
边界后,你可能想回到服务器环境。例如,你可能想减少客户端包的大小,在服务器上获取数据,或使用只在服务器上可用的 API。
即使理论上嵌套在客户端组件内,你也可以通过交错客户端和服务器组件以及服务器操作来保持代码在服务器上。有关更多信息,请参阅组合模式页面。