0Pricing
React Academy · 课时

Next.js 中的服务器组件与客户端组件

决定何时添加 'use client',以及如何组合服务器端和客户端组件树。

Next.js 中的服务器组件与客户端组件 是 CoddyKit 上的免费 React Academy 课时。 这是第 2 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 React Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 React Academy 课程共包含 4 节课。

默认设置:服务器组件

在 App Router 中,所有组件默认都是服务器组件。它们在服务器上渲染,不包含客户端 JavaScript,并且可以直接访问数据库、环境变量和文件系统。

选择使用客户端组件

在文件顶部添加 'use client',即可将其设为客户端组件。它导入的所有内容也会转为客户端代码——这会创建一个客户端边界。

'use client';

import { useState } from 'react';

export function Counter() {
  const [count, setCount] = useState(0);
  return <button onClick={() => setCount(c => c + 1)}>{count}</button>;
}

服务器组件可以做什么

服务器组件可以直接 await 数据获取、读取环境变量、访问文件系统,以及导入大型的仅限服务器端使用的程序包,而不会增加客户端捆绑包的大小。

// app/products/page.tsx — Server Component
export default async function ProductsPage() {
  const products = await db.query('SELECT * FROM products');
  return (
    <ul>
      {products.map(p => <li key={p.id}>{p.name}</li>)}
    </ul>
  );
}

服务器组件无法做什么

服务器组件无法使用钩子(useState、useEffect)、浏览器 API 或事件处理器。这些功能需要 'use client'。

组合服务器组件与客户端组件

将服务器组件的输出作为属性或子元素传递给客户端组件。推荐模式是:在服务器组件中获取数据,在客户端组件中处理交互。

// Server Component (no 'use client')
async function ProductPage({ id }) {
  const product = await getProduct(id); // direct DB call
  return <AddToCartButton product={product} />; // client component
}

// Client Component
'use client';
function AddToCartButton({ product }) {
  const [added, setAdded] = useState(false);
  return <button onClick={() => { addToCart(product); setAdded(true); }}>{added ? 'Added!' : 'Add to cart'}</button>;
}

将子元素从服务器传递到客户端

服务器组件可以将 JSX 作为 children 传递给客户端组件。子元素仍会在服务器上渲染;客户端包装器则添加交互功能。

// Client wrapper — Modal with open/close state
'use client';
function Modal({ children }) {
  const [open, setOpen] = useState(false);
  return (
    <>
      <button onClick={() => setOpen(true)}>Open</button>
      {open && <dialog>{children}</dialog>}
    </>
  );
}

// Server Component — passes server-fetched content into client modal
async function Page() {
  const content = await fetchContent();
  return <Modal><ServerRenderedContent data={content} /></Modal>;
}

客户端边界

添加 'use client' 会使该文件及其所有子级导入项在客户端运行。若要让子组件继续作为服务器组件,请将其作为属性或插槽传递,而不是直接导入。

数据获取模式

在服务器组件中获取数据,然后向下传递。尽可能避免在客户端组件中获取数据——这会增加客户端捆绑包的大小,并重复服务器端逻辑。

// Good: fetch in server, pass to client
async function Page() {
  const user = await getUser();
  return <UserProfile user={user} />; // client component
}

// Avoid: fetch in client
'use client';
function UserProfile() {
  const { data } = useSWR('/api/user', fetcher); // network request from browser
}

仅限服务器端的工具

如果仅限服务器端的模块被意外导入客户端组件,server-only 程序包会抛出构建错误。

// lib/db.ts
import 'server-only'; // throws at build time if imported in 'use client' file

export const db = createDbClient(process.env.DB_URL);

在服务器与客户端之间共享状态

服务器组件无法保存状态。若要将服务器获取的数据与可交互的客户端组件共享,请在初次渲染时将其作为属性传递,然后在客户端管理更新。

何时添加 use client

在需要以下功能时添加 'use client':钩子(useState、useEffect)、浏览器事件(onClick)、浏览器 API(localStorage、window)或第三方客户端程序库。

快速检查

要在 Next.js App Router 中使用 useState 或 onClick,必须在文件顶部添加什么?

回顾

所有 App Router 组件默认都是服务器组件——客户端捆绑包中不包含 JS,并且可以直接访问数据。只在需要交互功能的地方添加 'use client'。通过将服务器获取的数据作为属性或子元素传递给客户端包装器来进行组合,并尽可能将客户端边界放在叶级组件。

常见问题解答

「Next.js 中的服务器组件与客户端组件」课时是免费的吗?

是的 — 「Next.js 中的服务器组件与客户端组件」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 React Academy 课程的其余内容,请升级到 CoddyKit PRO。 React Academy 课程共包含 4 节课。

「Next.js 中的服务器组件与客户端组件」这节课中我会学到什么?

决定何时添加 'use client',以及如何组合服务器端和客户端组件树。 你通过在浏览器中直接运行的动手代码来练习 React Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 React Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 React Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 2 节课,共 4 节。

「Next.js 中的服务器组件与客户端组件」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 React Academy 课中编写并运行代码吗?

能。每节 React Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. App Router 文件约定
  2. Next.js 中的服务器组件与客户端组件
  3. 动态路由与路由组
  4. App Router 中的元数据 API 与 SEO
← 返回 React Academy