Next.js 客户端组件(Client Components)与服务端组件(Server Components)详解

张开发
2026/5/6 14:31:01 15 分钟阅读

分享文章

Next.js 客户端组件(Client Components)与服务端组件(Server Components)详解
本文基于 Next.js 官方文档Server and Client Components整理覆盖使用场景、渲染原理、组合规则、最佳实践。一、核心定位默认类型App Router 中layout.tsx/page.tsx默认为服务端组件Server Components。分工原则按运行环境拆分逻辑——服务端管渲染与数据客户端管交互与浏览器 API。二、使用场景官方明确边界1. 客户端组件 Client Components必须加use client满足以下任一需求时使用需要组件状态useState/useReducer/useRef需要事件处理onClick/onChange等需要生命周期useEffect需要浏览器专属 APIwindow/localStorage/navigator需要自定义 Hooks、React Context第三方交互组件轮播、图表、富文本2. 服务端组件 Server Components默认无需标记满足以下任一需求时使用就近获取数据直连数据库、接口无额外 API 层安全使用密钥API Key、Token 不暴露到客户端减少客户端 JS 体积服务端渲染不发 JS 到浏览器提升首屏性能优化 FCP支持流式渲染纯展示、无交互的静态内容文章、标题、列表三、渲染运行原理官方流程1. 服务端渲染阶段服务端组件渲染为RSC PayloadReact 服务端组件二进制结构客户端组件代码 RSC 用于预渲染HTML按路由分段layout / page拆分支持流式传输2. 客户端首次加载先展示非交互 HTML快速呈现内容用 RSC 对齐服务端/客户端组件树对客户端组件执行水合hydration绑定事件变可交互3. 后续导航预加载 缓存 RSC实现秒切路由客户端组件完全在浏览器渲染不再服务端生成 HTML关键概念RSC Payload服务端组件渲染结果客户端组件占位与 JS 引用服务端 → 客户端的可序列化 props四、基础写法规范1. 声明方式服务端组件无指令默认就是客户端组件文件顶部第一行加use client必须在所有 import 之前// 客户端组件示例 use client import { useState } from react export default function Counter() { const [count, setCount] useState(0) return button onClick{() setCount(count1)}{count}/button }2. 数据传递服务端 → 客户端用Props传递必须可序列化客户端 → 服务端不直接传组件只能传可序列化数据五、组件组合模式官方推荐1. 服务端嵌套客户端最常用页面/布局服务端→ 嵌入交互按钮/表单客户端服务端取数通过 props 传给客户端做交互// page.tsx服务端 import LikeButton from ./LikeButton export default async function Page({ params }) { const post await getPost(params.id) return LikeButton likes{post.likes} / }2. 客户端嵌套服务端客户端组件用children作为插槽服务端组件作为子元素传入仍在服务端渲染示例弹窗客户端包裹购物车服务端// Modal客户端 use client export default function Modal({ children }) { return div{children}/div } // Page服务端 import Modal from ./Modal import Cart from ./Cart // 服务端组件 export default function Page() { return ModalCart //Modal }3. Context 提供者Context 只能在客户端组件创建在根布局服务端引入包裹全局实现全局状态共享// ThemeProvider客户端 use client import { createContext } from react export const ThemeContext createContext() export default function ThemeProvider({ children }) { return ThemeContext.Provider valuedark{children}/ThemeContext.Provider } // 根布局服务端 import ThemeProvider from ./ThemeProvider export default function RootLayout({ children }) { return htmlbodyThemeProvider{children}/ThemeProvider/body/html }4. 第三方组件兼容依赖客户端特性的库需包裹一层use client再使用库作者应在入口加use client方便用户直接使用六、性能与安全最佳实践最小化客户端边界只给真正需要交互的组件加use client避免整页变成客户端组件减小 bundle 体积。环境隔离防污染服务端代码用server-only包防止被引入客户端客户端代码可用client-only标记浏览器专属逻辑环境变量非NEXT_PUBLIC_前缀不会注入客户端防密钥泄露Provider 尽量下沉不要包裹整个html缩小客户端渲染范围优化服务端静态内容缓存七、快速判断口诀官方思路要交互、状态、浏览器 API→ 客户端组件use client要取数、安全、减包、提速→ 服务端组件默认服务端管数据与渲染客户端管交互组合使用最稳八、核心对比表维度服务端组件客户端组件声明默认无指令必须use client渲染位置服务端客户端交互能力无完整state/effect/事件数据获取直连数据库/API只能走接口安全密钥可安全使用不可暴露客户端 JS零打包需发送 JS首屏性能优一般适用场景展示、取数、SEO交互、状态、浏览器 API

更多文章