【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
相关推荐
Mintopia1 小时前
合合信息蜜蜂 AI 最新资讯(2026.4.22 官方发布)
前端
Mintopia1 小时前
如何用第一性原理提升问题解决能力
前端
ai产品老杨1 小时前
深度解析:基于异构计算的工业级AI视频中台架构,支持GB28181/RTSP接入与X86/ARM/NPU全场景部署
人工智能·架构·音视频
禅思院1 小时前
下篇:打造可观测的异步加载防御体系
前端·架构·前端框架
RTC老炮1 小时前
音视频FEC前向纠错算法Reed-Solomon原理分析
网络·算法·架构·音视频·webrtc
|晴 天|2 小时前
Vue 3 项目错误处理实战:Vue ErrorHandler、Promise 监控、用户友好提示
前端·javascript·vue.js
Cobyte2 小时前
8.响应式系统比对:手写 SolidJS 响应式系统
前端·javascript·vue.js
IT_陈寒2 小时前
Python中的这个可变默认参数陷阱我居然又踩了
前端·人工智能·后端
qiao若huan喜2 小时前
13、webgl基本概念 + 绘制狮子座星空
前端·javascript·信息可视化·webgl