【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
相关推荐
jiayong238 分钟前
第 44 课:任务详情抽屉里的评论输入与操作记录联动
前端
ndsc_d9 分钟前
前端实战复盘:用AI直接生成响应式官网落地页与React源码
前端·人工智能·react.js·ui·前端框架·aigc·paico
带娃的IT创业者22 分钟前
当推理速度突破物理极限:深度解析 MiMo-v2.5-Pro-UltraSpeed 的 1000 TPS 架构革命
人工智能·架构·大模型·架构优化·mimo·tps·推理速度
大家的林语冰1 小时前
✌️ Deno 2.9 来了,ESM 直接导入 CSS,甚至能开发桌面应用?!
前端·javascript·node.js
一枚码农出身的猎头1 小时前
岗位招聘:架构师,base湖南长沙,70-80w
java·架构
李顿波1 小时前
前端样式技术发展进程和解析(长期更新版)
前端
2601_954706491 小时前
云虚拟化终端架构解析:ARM 云端集群部署与自动化运维实践
运维·arm开发·架构
米尔的可达鸭1 小时前
深入操作系统 Socket 底层:套接字控制块、FD映射、阻塞IO核心完整实现
arm开发·数据结构·websocket·网络协议·算法·架构·安全架构
春卷同学1 小时前
HarmonyOS掌上记账APP开发实践第1篇:HarmonyOS 多模块 HAR 架构最佳实践 — MoneyTrack 多模块拆分之道
华为·架构·harmonyos
不简说2 小时前
JS 代码技巧 vol.1 — 10 个让代码少写 30% 的小套路
前端·javascript·面试