名称: react-server-components-framework 描述: 使用 Next.js 15 App Router 设计和实现 React 服务器组件。掌握服务器优先架构、流式 SSR、服务器操作以及面向 2025+ 前端开发的现代数据获取模式。 版本: 1.0.0 作者: AI Agent Hub 标签: [前端, react, nextjs, 服务器组件, 流式, 2025]
React 服务器组件框架
概述
React 服务器组件代表了 React 架构的范式转变,实现了服务器优先渲染与客户端交互性。本技能提供了使用 App Router 构建现代 Next.js 15 应用程序的全面模式、模板和最佳实践,涵盖服务器组件、服务器操作和流式渲染。
何时使用此技能:
- 使用 App Router 构建 Next.js 15+ 应用程序
- 设计组件边界(服务器组件 vs 客户端组件)
- 实现带缓存和重新验证的数据获取
- 使用服务器操作创建数据变更
- 通过流式渲染和 Suspense 优化性能
- 实现部分预渲染
- 设计高级路由模式(并行路由、拦截路由)
为何 React 服务器组件重要
RSC 从根本上改变了我们对 React 应用程序的思考方式:
- 服务器优先架构:组件默认在服务器端渲染,减少客户端包大小
- 零客户端包:服务器组件不向客户端发送 JavaScript
- 直接后端访问:直接从组件访问数据库、文件系统和 API
- 自动代码分割:仅客户端组件及其依赖项被打包
- 流式渲染与 Suspense:渐进式渲染以实现即时感知性能
- 类型安全的数据获取:从数据库到 UI 的端到端 TypeScript
- SEO 与性能:服务器渲染改善了核心 Web 指标和 SEO
核心概念
1. 服务器组件 vs 客户端组件
服务器组件(默认):
- 可以是
async并使用await - 直接访问数据库
- 不能使用钩子或浏览器 API
- 零客户端 JavaScript
客户端组件(使用 'use client'):
- 可以使用钩子(
useState、useEffect等) - 浏览器 API 可用
- 不能是
async - 向客户端发送 JavaScript
关键规则:服务器组件可以渲染客户端组件,但客户端组件不能直接导入服务器组件(应使用 children 属性传递)。
详细模式:请参阅 references/component-patterns.md 了解:
- 完整的组件边界规则
- 组合模式
- 属性传递策略
- 常见陷阱和解决方案
2. 数据获取
Next.js 扩展了 fetch API,提供了强大的缓存和重新验证功能:
// 静态(无限期缓存)
await fetch(url, { cache: 'force-cache' })
// 每 60 秒重新验证
await fetch(url, { next: { revalidate: 60 } })
// 始终获取最新
await fetch(url, { cache: 'no-store' })
// 基于标签的重新验证
await fetch(url, { next: { tags: ['posts'] } })
模式:
- 并行获取:
Promise.all([fetch1, fetch2, fetch3]) - 顺序获取:当数据依赖于先前结果时
- 路由段配置:控制静态/动态渲染
详细实现:请参阅 references/data-fetching.md 了解:
- 完整的缓存策略
- 重新验证方法(
revalidatePath、revalidateTag) - 服务器组件中的数据库查询
- 用于 SSG 的 generateStaticParams
- 错误处理模式
3. 服务器操作
服务器操作无需 API 路由即可实现数据变更:
// app/actions.ts
'use server'
export async function createPost(formData: FormData) {
const title = formData.get('title') as string
const post = await db.post.create({ data: { title } })
revalidatePath('/posts')
redirect(`/posts/${post.id}`)
}
渐进增强:表单无需 JavaScript 即可工作,然后通过客户端状态进行增强。
详细实现:请参阅 references/server-actions.md 了解:
- 渐进增强模式
- useFormStatus 和 useFormState 钩子
- 使用 useOptimistic 的乐观 UI
- 使用 Zod 进行验证
- 内联 vs 导出的服务器操作
4. 使用 Suspense 进行流式渲染
独立流式渲染组件以获得更好的感知性能:
import { Suspense } from 'react'
export default function Dashboard() {
return (
<div>
<Suspense fallback={<ChartSkeleton />}>
<RevenueChart />
</Suspense>
<Suspense fallback={<InvoicesSkeleton />}>
<LatestInvoices />
</Suspense>
</div>
)
}
好处:
- 内容准备就绪时立即显示
- 非阻塞数据获取
- 更好的核心 Web 指标
模板:使用 templates/ServerComponent.tsx 获取流式渲染模式
5. 高级路由
并行路由:同时渲染多个页面
app/
@team/page.tsx
@analytics/page.tsx
layout.tsx # 接收两者作为属性
拦截路由:显示模态框同时保留 URL
app/
photos/[id]/page.tsx # 直接路由
(..)photos/[id]/page.tsx # 被拦截的路由(模态框)
部分预渲染:混合静态和动态内容
export const experimental_ppr = true
// 静态外壳 + 动态 Suspense 边界
详细实现:请参阅 references/routing-patterns.md 了解:
- 并行路由布局实现
- 用于模态框的拦截路由
- PPR 配置和模式
- 用于组织的路由组
- 动态路由、全捕获路由和可选全捕获路由
搜索参考资料
使用 grep 在参考资料中查找特定模式:
# 查找组件模式
grep -r "Server Component" references/
# 搜索数据获取策略
grep -A 10 "Caching Strategies" references/data-fetching.md
# 查找服务器操作示例
grep -B 5 "Progressive Enhancement" references/server-actions.md
# 定位路由模式
grep -n "Parallel Routes" references/routing-patterns.md
# 搜索迁移指南
grep -i "pages router\|getServerSideProps" references/migration-guide.md
最佳实践
组件边界设计
- ✅ 将客户端组件保持在组件树的边缘(叶子节点)
- ✅ 默认使用服务器组件
- ✅ 将最小的交互部分提取到客户端组件
- ✅ 将服务器组件作为
children传递给客户端组件 - ❌ 避免将整个页面设为客户端组件
数据获取
- ✅ 在靠近使用位置的服务器组件中获取数据
- ✅ 对独立数据使用并行获取
- ✅ 设置适当的缓存和重新验证选项
- ✅ 对静态路由使用
generateStaticParams - ❌ 不要在客户端组件中使用 useEffect 获取数据(使用服务器组件)
性能
- ✅ 使用 Suspense 边界进行流式渲染
- ✅ 实现 loading.tsx 以提供即时加载状态
- ✅ 启用 PPR 以混合静态/动态内容
- ✅ 使用 next/image 优化图像
- ✅ 使用路由段配置来控制渲染模式
错误处理
- ✅ 实现 error.tsx 作为错误边界
- ✅ 使用 not-found.tsx 作为 404 页面
- ✅ 优雅地处理 fetch 错误
- ✅ 验证服务器操作输入
模板
使用提供的模板处理常见模式:
templates/ServerComponent.tsx- 带有数据获取的基本异步服务器组件templates/ClientComponent.tsx- 带有钩子的交互式客户端组件templates/ServerAction.tsx- 带有验证和重新验证的服务器操作
示例
完整博客应用
请参阅 examples/blog-app/ 获取完整实现:
- 用于文章列表和详情的服务器组件
- 用于评论和点赞的客户端组件
- 用于创建/编辑文章的服务器操作
- 使用 Suspense 进行流式渲染
- 用于仪表板的并行路由
检查清单
RSC 实现检查清单
请参阅 checklists/rsc-implementation.md 获取涵盖以下内容的全面验证:
- [ ] 正确定义组件边界(服务器 vs 客户端)
- [ ] 使用适当缓存策略的数据获取
- [ ] 用于数据变更的服务器操作
- [ ] 对慢速组件使用 Suspense 进行流式渲染
- [ ] 错误处理(error.tsx、not-found.tsx)
- [ ] 加载状态(loading.tsx)
- [ ] 用于 SEO 的元数据 API
- [ ] 优化的路由段配置
常见模式
使用 URL 状态进行搜索
// app/search/page.tsx
export default async function SearchPage({
searchParams,
}: {
searchParams: { q?: string }
}) {
const query = searchParams.q || ''
const results = query ? await searchProducts(query) : []
return (
<div>
<SearchForm initialQuery={query} />
<SearchResults results={results} />
</div>
)
}
身份验证
import { cookies } from 'next/headers'
export default async function DashboardPage() {
const token = cookies().get('token')?.value
const user = await verifyToken(token)
if (!user) {
redirect('/login')
}
return <Dashboard user={user} />
}
乐观 UI
'use client'
import { useOptimistic } from 'react'
export function TodoList({ todos }) {
const [optimisticTodos, addOptimisticTodo] = useOptimistic(
todos,
(state, newTodo) => [...state, newTodo]
)
return <ul>{/* 渲染 optimisticTodos */}</ul>
}
从 Pages Router 迁移
增量采用:pages/ 和 app/ 可以共存
关键变更:
getServerSideProps→ 异步服务器组件getStaticProps→ 带缓存的异步服务器组件- API 路由 → 服务器操作
_app.tsx→layout.tsx<Head>→generateMetadata函数
详细迁移:请参阅 references/migration-guide.md 了解:
- 分步迁移指南
- 迁移前后代码示例
- 常见迁移陷阱
- 布局和元数据迁移模式
故障排除
错误:“您正在导入一个需要 useState 的组件”
- 修复:向组件添加
'use client'指令
错误:“async/await 在非异步服务器组件中无效”
- 修复:向函数声明添加
async
错误:“不能在客户端组件内部使用服务器组件”
- 修复:将服务器组件作为
children属性传递,而不是导入
错误:“水合不匹配”
- 修复:对使用
Date.now()、Math.random()或浏览器 API 的组件使用'use client'
资源
后续步骤
掌握 React 服务器组件后:
- 探索 流式 API 模式 技能以获取实时数据
- 使用 类型安全与验证 技能进行 tRPC 集成
- 应用 边缘计算模式 技能进行全球部署
- 参考 性能优化 技能以改善核心 Web 指标