【Next】客户端组件和服务端组件

概述

在 Next.js(尤其是 App Router 体系)里,客户端组件(Client Component)和服务端组件(Server Component) 是基于 React 的 RSC(React Server Components)模型实现的。

  • 服务端组件(Server Component)默认执行在服务端(Node.js),用于数据获取、减少 bundle
  • 客户端组件(Client Component)运行在浏览器,用于交互、状态、事件
  • 二者通过 序列化协议(Flight) 进行通信
能力 Server Client
访问数据库
使用 useState
使用 useEffect
绑定事件 onClick
减少 bundle 体积
tsx 复制代码
// 默认就是 Server Component
export default function Page() {
  return <div>Hello</div>;
}
tsx 复制代码
// 显式声明 Client Component
"use client";

export default function Button() {
  return <button onClick={() => alert(1)}>Click</button>;
}

"use client" 是一个 编译时指令(不是运行时)

Server Component 深入

为什么默认是 Server?

核心目标:减少前端 bundle + 提升首屏性能

tsx 复制代码
// 直接在服务端查数据
async function Page() {
  const data = await fetch("https://api.com/user");
  return <div>{data.name}</div>;
}
  • ❌ 不需要把 fetch 逻辑打包到浏览器
  • ❌ 不需要 useEffect + loading
  • ✅ SSR 天然支持

可以直接访问后端资源

ts 复制代码
import db from "@/lib/db";

export default async function Page() {
  const users = await db.user.findMany();
  return <div>{users.length}</div>;
}
  • Prisma
  • 内部 RPC(BFF)
  • GraphQL

不支持交互

tsx 复制代码
// ❌ 错误
export default function Page() {
  return <button onClick={() => {}}>Click</button>;
}
  • Server Component 不会在浏览器执行
  • 没有事件系统

Client Component 深入

只要涉及以下任意一点,就需要使用客户端组件:

  • useState
  • useEffect
  • DOM 操作
  • 事件(onClick)
  • 浏览器 API(localStorage)
tsx 复制代码
"use client";

import { useState } from "react";

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

  return (
    <button onClick={() => setCount(count + 1)}>
      {count}
    </button>
  );
}
  • 会被打进 JS bundle
  • 会增加 hydration 成本
  • 会影响 TTI

所以 能不用 client 就不用

核心机制

Server → Client 的传输原理(Flight)

Server Component 渲染后不会直接输出 HTML,而是:

输出一种特殊 JSON(React Flight)

示意:

json 复制代码
[
  ["div", null, "Hello"],
  ["$L1", "Button"]
]

客户端再:

  • 解析结构
  • 加载对应 Client Component
  • Hydration

限制:只能传"可序列化数据"

tsx 复制代码
// ❌ 错误
<ClientComp fn={() => {}} />
tsx 复制代码
// ✅ 正确
<ClientComp count={1} />

因为需要跨网络传输

组合模式

推荐结构:Server + Client 嵌套

tsx 复制代码
// Server Component
import Button from "./Button";

export default async function Page() {
  const data = await fetchData();

  return (
    <div>
      <h1>{data.title}</h1>
      <Button />
    </div>
  );
}
tsx 复制代码
// Client Component
"use client";

export default function Button() {
  return <button>Click</button>;
}

注意: Client 不能 import Server

tsx 复制代码
// ❌ 错误
"use client";
import ServerComp from "./ServerComp";
tsx 复制代码
// ✅ Server 可以 import Client
相关推荐
萧行之22 分钟前
可视化技术复盘:从图形语法看 D3、Vega-Lite、ECharts、Observable Plot
前端·学习·数据可视化
mldong7 小时前
一个 App,十三套后端:手机审批端 uni-jeeflow-app 开源了
java·架构
尾善爱看海8 小时前
Vue 面试收官篇:SSR、性能优化落地、30 道高频面试题精讲(附标准答案)
前端·javascript·vue.js·面试·vue
weixin_BYSJ19878 小时前
【计算机毕设】基于SpringBoot与Vue的文物保护档案管理系统08621
vue.js·spring boot·spring cloud·微服务·架构·django·课程设计
GreenTea8 小时前
7000 万 QPS、500 PB:OpenAI 如何用一个 Python 存储平台撑住 10 亿用户
后端·架构
西安栈上月明软件科技9 小时前
从业务黑话到本体图谱:OAG本体建模五步法(西安老系统AI化改造实战)
数据库·人工智能·架构
驳是9 小时前
一个组件,提升 react-router 开发的幸福感
前端·preact
GreenTea9 小时前
OpenAI Agents API 上手实测:一次调用把整个 agent loop 甩给 OpenAI
前端·后端·算法
星云API技术支持9 小时前
企业微信二次开发:群权限设置、成员管理与群资料维护的接口组合实践
java·前端·企业微信
京东云开发者9 小时前
81.8 秒的视频,我们改了 15 个版本:一次纯 Codex 驱动的 AI-native 视频实践
前端·aigc