一、缘起:为什么需要 Server Components?# 2020 年底,React 团队在 RFC 中首次提出了 Server Components 的概念。 当时社区一片哗然——"React 不是客户端框架吗?服务端渲染(SSR)不是已经有 Next.js 做了吗?" 答案藏在两个核心痛点里: 瀑布式数据请求。 传统的 CSR 应用中,组件树渲染 → 发现数据依赖 → 发起请求 → 等待响应,层层递进,像多米诺骨牌一样依次倒下。 客户端 JS 体积膨胀。 日期格式化库、Markdown 解析器、语法高亮…… 这些"纯函数"般的依赖占据了最终 bundle 的 40% 以上,但它们本就不需要 在浏览器里运行。 二、核心心智模型# RSC 的精髓在于一个简单的二元划分: 类型 运行环境 能力 Server Component(默认) 服务端 直接访问数据库/文件系统、import 重型库、Node.js API Client Component 浏览器 useState、useEffect、事件处理、浏览器 API // ✅ server-component.tsx —— 默认就是服务端组件 import { db } from "@/lib/db"; export default async function PostList() { const posts = await db.post.findMany(); // 直接查数据库,零客户端 JS! return ( <ul> {posts.map(p => <li key={p.id}>{p.title}</li>)} </ul> ); } // ✅ client-component.tsx —— 'use client' 边界标记 'use client'; import { useState } from 'react'; export default function LikeButton({ postId }: { postId: string }) { const [liked, setLiked] = useState(false); return ( <button onClick={() => setLiked(!liked)}> {liked ? '❤️' : '🤍'} </button> ); } 三、实践中的三个关键决策# 1. 服务端组件 vs 客户端组件的边界在哪里?# 我的原则:叶子节点优先客户端,数据流优先服务端。 列表容器 → 服务端(数据获取) 列表项交互按钮 → 客户端(事件处理) 评论区展示 → 服务端(首屏渲染) 评论输入框 → 客户端(表单交互) 2. 如何优雅地传递数据?# 避免 prop drilling 的最佳实践:在服务端组件中完成所有数据获取, 通过 props 向下传递给客户端组件。服务端组件可以嵌套客户端组件, 但反过来不行——'use client' 是单向边界。 3. 第三方库的兼容性# 大部分 UI 库(如 Radix UI、Headless UI)已经全面支持 RSC。 对于尚未适配的库(如某些图表库),使用 dynamic(() => import(...), { ssr: false }) 包裹即可。 四、总结# RSC 不是对现有模式的推翻,而是补充。它让 React 从"一刀切的客户端渲染" 进化为"在组件粒度上自由选择运行时"。这是一种对开发者友好的渐进式变革—— 你可以从一个组件开始,逐步将数据获取逻辑迁移到服务端,而不需要重写整个应用。 最好的架构,是让正确的代码运行在正确的地方。
一、缘起:为什么需要 Server Components?#
2020 年底,React 团队在 RFC 中首次提出了 Server Components 的概念。 当时社区一片哗然——"React 不是客户端框架吗?服务端渲染(SSR)不是已经有 Next.js 做了吗?"
答案藏在两个核心痛点里:
二、核心心智模型#
RSC 的精髓在于一个简单的二元划分:
三、实践中的三个关键决策#
1. 服务端组件 vs 客户端组件的边界在哪里?#
我的原则:叶子节点优先客户端,数据流优先服务端。
2. 如何优雅地传递数据?#
避免 prop drilling 的最佳实践:在服务端组件中完成所有数据获取, 通过 props 向下传递给客户端组件。服务端组件可以嵌套客户端组件, 但反过来不行——'use client' 是单向边界。
3. 第三方库的兼容性#
大部分 UI 库(如 Radix UI、Headless UI)已经全面支持 RSC。 对于尚未适配的库(如某些图表库),使用
dynamic(() => import(...), { ssr: false })包裹即可。四、总结#
RSC 不是对现有模式的推翻,而是补充。它让 React 从"一刀切的客户端渲染" 进化为"在组件粒度上自由选择运行时"。这是一种对开发者友好的渐进式变革—— 你可以从一个组件开始,逐步将数据获取逻辑迁移到服务端,而不需要重写整个应用。