名称: react-server-components 描述: 包含流式传输、数据获取、客户端/服务器组件组合和性能优化的React服务器组件模式。 允许工具: 读取、写入、编辑、Bash、Glob、Grep
React服务器组件技能
为实施具有正确模式和组合策略的React服务器组件提供专家协助。
能力
- 设计服务器/客户端组件边界
- 使用Suspense实现流式传输
- 在服务器组件中处理数据获取
- 组合服务器和客户端组件
- 通过选择性水合优化性能
- 管理用于变更的服务器操作
使用场景
在以下情况下调用此技能:
- 构建RSC应用程序架构
- 实现流式数据获取
- 确定服务器与客户端组件
- 将服务器数据传递给客户端组件
- 为表单构建服务器操作
输入参数
| 参数 | 类型 | 是否必需 | 描述 |
|---|---|---|---|
| componentType | 字符串 | 是 | 服务器、客户端、共享 |
| dataFetching | 布尔值 | 否 | 组件是否获取数据 |
| interactivity | 数组 | 否 | 所需的客户端交互 |
| streaming | 布尔值 | 否 | 是否启用流式传输 |
配置示例
{
"componentType": "server",
"dataFetching": true,
"streaming": true,
"childComponents": [
{ "name": "InteractiveChart", "type": "client" }
]
}
组件模式
服务器组件(默认)
// app/users/page.tsx - 默认服务器组件
import { db } from '@/lib/db';
import { UserCard } from './user-card';
async function getUsers() {
return db.user.findMany({
include: { posts: true },
});
}
export default async function UsersPage() {
const users = await getUsers();
return (
<div className="grid gap-4">
<h1>用户列表</h1>
{users.map((user) => (
<UserCard key={user.id} user={user} />
))}
</div>
);
}
客户端组件
// components/interactive-counter.tsx
'use client';
import { useState } from 'react';
export function InteractiveCounter({ initialCount }: { initialCount: number }) {
const [count, setCount] = useState(initialCount);
return (
<div>
<p>计数: {count}</p>
<button onClick={() => setCount(c => c + 1)}>
增加
</button>
</div>
);
}
组合模式
// app/dashboard/page.tsx - 服务器组件
import { Suspense } from 'react';
import { db } from '@/lib/db';
import { InteractiveChart } from '@/components/interactive-chart';
import { ChartSkeleton } from '@/components/skeletons';
async function getAnalytics() {
return db.analytics.findMany({
orderBy: { date: 'desc' },
take: 30,
});
}
export default async function Dashboard() {
const analytics = await getAnalytics();
return (
<div>
<h1>仪表板</h1>
{/* 将服务器数据传递给客户端组件 */}
<Suspense fallback={<ChartSkeleton />}>
<InteractiveChart data={analytics} />
</Suspense>
</div>
);
}
// components/interactive-chart.tsx - 客户端组件
'use client';
import { useState } from 'react';
import { LineChart } from 'recharts';
interface ChartProps {
data: AnalyticsData[];
}
export function InteractiveChart({ data }: ChartProps) {
const [timeRange, setTimeRange] = useState('7d');
const filteredData = filterByTimeRange(data, timeRange);
return (
<div>
<select
value={timeRange}
onChange={(e) => setTimeRange(e.target.value)}
>
<option value="7d">最近7天</option>
<option value="30d">最近30天</option>
</select>
<LineChart data={filteredData} />
</div>
);
}
使用Suspense的流式传输
// app/page.tsx
import { Suspense } from 'react';
import { SlowComponent, FastComponent } from '@/components';
export default function Page() {
return (
<div>
{/* 快速内容立即渲染 */}
<FastComponent />
{/* 慢速内容流式加载 */}
<Suspense fallback={<p>加载慢速内容中...</p>}>
<SlowComponent />
</Suspense>
</div>
);
}
// components/slow-component.tsx
async function getSlowData() {
await new Promise((resolve) => setTimeout(resolve, 2000));
return { data: '慢速数据已加载' };
}
export async function SlowComponent() {
const data = await getSlowData();
return <div>{data.data}</div>;
}
服务器操作
// app/actions.ts
'use server';
import { revalidatePath } from 'next/cache';
import { db } from '@/lib/db';
export async function createUser(formData: FormData) {
const name = formData.get('name') as string;
const email = formData.get('email') as string;
await db.user.create({
data: { name, email },
});
revalidatePath('/users');
}
export async function updateUser(id: string, formData: FormData) {
const name = formData.get('name') as string;
await db.user.update({
where: { id },
data: { name },
});
revalidatePath(`/users/${id}`);
}
// components/user-form.tsx
'use client';
import { useFormStatus } from 'react-dom';
import { createUser } from '@/app/actions';
function SubmitButton() {
const { pending } = useFormStatus();
return (
<button type="submit" disabled={pending}>
{pending ? '创建中...' : '创建用户'}
</button>
);
}
export function UserForm() {
return (
<form action={createUser}>
<input name="name" placeholder="姓名" required />
<input name="email" type="email" placeholder="邮箱" required />
<SubmitButton />
</form>
);
}
将服务器组件作为Props传递
// 模式:服务器组件作为子组件
// app/page.tsx
import { ClientWrapper } from '@/components/client-wrapper';
import { ServerContent } from '@/components/server-content';
export default function Page() {
return (
<ClientWrapper>
<ServerContent />
</ClientWrapper>
);
}
// components/client-wrapper.tsx
'use client';
export function ClientWrapper({ children }: { children: React.ReactNode }) {
const [isOpen, setIsOpen] = useState(true);
return (
<div>
<button onClick={() => setIsOpen(!isOpen)}>切换</button>
{isOpen && children}
</div>
);
}
决策框架
使用服务器组件的情况:
- 获取数据
- 直接访问后端资源
- 将敏感信息保留在服务器上
- 将大型依赖项保留在服务器上
- 不需要交互性
使用客户端组件的情况:
- 使用useState、useEffect、useReducer
- 使用浏览器API
- 添加事件监听器
- 使用带有状态的自定义钩子
- 使用React Context提供者
最佳实践
- 默认使用服务器组件
- 将客户端边界向下推
- 向客户端组件传递可序列化的props
- 使用Suspense进行流式传输
- 将数据获取与组件放在一起
目标流程
- nextjs全栈开发
- react服务器组件迁移
- 性能优化
- 流式传输实现