React 19 + Server Components 实战:完整迁移指南
React Server Components 在 2026 年已经成熟。本文用真实电商项目演示从 Pages Router 到 App Router + RSC 的完整迁移。
今日技术简讯
📰 技术简讯 · 2026-06-09
今日聚合 7 条热门技术内容。
🤖 AI / LLM
1. Claude 4.1 推出 Computer Use GA
- 链接:https://www.anthropic.com/news/computer-use-ga
- 来源:Anthropic
- 摘要:Computer Use 进入 GA,企业用户可在生产环境使用,已通过 SOC 2 认证。
2. Mistral 发布 Codestral 25B
- 链接:https://mistral.ai/news/codestral-25b
- 来源:Mistral
- 摘要:25B 参数的代码专用模型,单 GPU 即可运行,性能接近 Claude 4。
🎨 前端 / Web
3. React 19 + RSC 实战经验
- 链接:https://react.dev/blog/rsc-2026
- 来源:React 官方
- 摘要:RSC 进入稳定版 1 年,Vercel / Netflix / Notion 分享实战经验。
4. TanStack Query 5 进入 RC
- 链接:https://tanstack.com/query
- 来源:Tanner Linsley
- 摘要:新版大幅简化 API,与 RSC 集成更顺滑。
⚙️ 后端 / 架构
5. Postgres 进入 ML 时代:pgai 0.5
- 链接:https://github.com/timescale/pgai
- 来源:Timescale
- 摘要:pgai 让 PostgreSQL 原生支持向量 + ML 推理,一库多用。
🚀 独立开发 / OPC
6. 《Indie Founder Playbook》第三版发布
- 链接:https://playbook.indiehackers.com
- 来源:Indie Hackers
- 摘要:100+ 章节,覆盖产品 / 营销 / 财务 / 心理。
7. Resend 推出 Marketing API
- 链接:https://resend.com/blog/marketing-api
- 来源:Resend
- 摘要:邮件营销 API,开发者友好,免费 3000 封/月。
数据来源:HN / Reddit / 各厂博客 采集时间:2026-06-09 09:00 (UTC+8)
今日深度文
React 19 + Server Components 实战:完整迁移指南
一句话结论:RSC 不是"另一种 SSR",而是"前端架构的重新定义"。迁移成本不低,但收益巨大。
背景
React Server Components(RSC)从 2023 年提出,到 2026 年已经成熟:
- Next.js 16 完全基于 RSC(默认所有组件是 Server Component)
- Vite + React 19 支持 RSC
- 各大厂生产环境使用:Vercel / Netflix / Notion / GitHub
但 RSC 是一个架构变革,不是简单的 API 变化。下面是真实迁移经验。
RSC 的核心概念
传统 React 组件(Client Component)
// app/products/page.tsx - 传统写法
'use client';
import { useState, useEffect } from 'react';
export default function Products() {
const [products, setProducts] = useState([]);
useEffect(() => {
fetch('/api/products')
.then(res => res.json())
.then(setProducts);
}, []);
return (
<div>
{products.map(p => <ProductCard key={p.id} product={p} />)}
</div>
);
}
问题:
- JS bundle 包含所有代码(即使只是展示)
- 用户看到 loading → 再看到内容(瀑布流)
- SEO 不友好(虽然有 Next.js 兜底)
Server Component
// app/products/page.tsx - RSC 写法
import { getProducts } from '@/lib/db';
export default async function Products() {
// 在服务器上直接查数据库
const products = await getProducts();
return (
<div>
{products.map(p => <ProductCard key={p.id} product={p} />)}
</div>
);
}
优势:
- ✅ 零 JS bundle(只在服务器跑一次)
- ✅ 首屏直达数据(无 loading)
- ✅ 完美 SEO
- ✅ 数据库访问不需要 API endpoint
Client Component(必须用 'use client')
// components/AddToCart.tsx
'use client';
import { useState } from 'react';
export function AddToCart({ productId }: { productId: string }) {
const [loading, setLoading] = useState(false);
return (
<button onClick={async () => {
setLoading(true);
await fetch('/api/cart', {
method: 'POST',
body: JSON.stringify({ productId })
});
setLoading(false);
}}>
{loading ? '加入中...' : '加入购物车'}
</button>
);
}
核心规则:
- 默认是 Server Component(无 JS)
- 需要交互 → 加
'use client' - Server Component 可以嵌套 Client Component
- Client Component 不能 import Server Component(边界问题)
真实案例:电商首页迁移
迁移前(Pages Router)
// pages/index.tsx
export async function getServerSideProps() {
const products = await fetchProducts();
const recommendations = await fetchRecommendations(user);
return { props: { products, recommendations } };
}
export default function Home({ products, recommendations }) {
return (
<div>
<Hero />
<ProductList products={products} />
<Recommendations items={recommendations} />
<Newsletter />
</div>
);
}
指标:
- JS bundle:420KB
- 首屏 LCP:2.8s
- SEO 评分:78
迁移后(App Router + RSC)
// app/page.tsx - 顶层 Server Component
import { getProducts } from '@/lib/db';
import { Hero } from '@/components/Hero';
import { ProductList } from '@/components/ProductList';
import { Recommendations } from '@/components/Recommendations';
import { Newsletter } from '@/components/Newsletter';
export default async function Home() {
// 并行数据获取
const [products, recommendations] = await Promise.all([
getProducts(),
getRecommendations(),
]);
return (
<div>
<Hero />
<ProductList products={products} />
<Recommendations items={recommendations} />
<Newsletter />
</div>
);
}
// 优化:用 Suspense 流式渲染
import { Suspense } from 'react';
export default function Home() {
return (
<div>
<Hero />
<Suspense fallback={<ProductListSkeleton />}>
<ProductList />
</Suspense>
<Suspense fallback={<RecommendationsSkeleton />}>
<Recommendations />
</Suspense>
<Newsletter />
</div>
);
}
指标:
- JS bundle:180KB(-57%)
- 首屏 LCP:1.2s(-57%)
- SEO 评分:96
5 个关键模式
模式 1:Server Component → Client Component 边界
// ✅ 正确:Server 包 Client
// app/dashboard/page.tsx (Server)
import { Chart } from './Chart'; // Client
export default async function Dashboard() {
const data = await getData();
return <Chart data={data} />;
}
// ❌ 错误:Client 试图 import Server
// components/Chart.tsx (Client)
import { ServerOnlyChart } from './ServerOnlyChart'; // 报错
技巧:把 Server Component 作为 children 传给 Client Component:
// components/Modal.tsx (Client)
'use client';
export function Modal({ children, isOpen }: {
children: React.ReactNode;
isOpen: boolean;
}) {
return isOpen ? <div className="modal">{children}</div> : null;
}
// app/dashboard/page.tsx (Server)
export default async function Page() {
const data = await getData();
return (
<Modal isOpen={true}>
<ServerChart data={data} /> {/* Server 在 Modal 里渲染 */}
</Modal>
);
}
模式 2:Streaming SSR
// app/products/page.tsx
import { Suspense } from 'react';
export default function ProductsPage() {
return (
<div>
<h1>产品列表</h1>
<Suspense fallback={<Skeleton />}>
<ProductList /> {/* Server Component 异步加载 */}
</Suspense>
</div>
);
}
async function ProductList() {
const products = await getProducts(); // 即使慢,也能先渲染其他部分
return products.map(p => <ProductCard key={p.id} product={p} />);
}
效果:用户立即看到骨架屏 + 标题,ProductList 加载好后自动填充。
模式 3:Server Actions(替代 API routes)
// app/actions.ts
'use server';
import { revalidatePath } from 'next/cache';
export async function addProduct(formData: FormData) {
const product = {
name: formData.get('name'),
price: Number(formData.get('price')),
};
await db.products.insert(product);
revalidatePath('/products'); // 重新渲染
}
// components/AddProductForm.tsx
'use client';
import { addProduct } from '@/app/actions';
export function AddProductForm() {
return (
<form action={addProduct}>
<input name="name" />
<input name="price" type="number" />
<button type="submit">添加</button>
</form>
);
}
优势:不用写 API endpoint,不用 fetch,不用管错误处理。
模式 4:共享组件的 Server / Client 双版本
// components/Button.tsx - 双版本
// Server 版本(无 JS)
export function Button({ children, ...props }: ButtonProps) {
return <button {...props}>{children}</button>;
}
// Client 版本(有 JS)
'use client';
export function ClientButton({ children, onClick, ...props }: ButtonProps) {
return <button onClick={onClick} {...props}>{children}</button>;
}
// 使用时按需导入
import { Button } from '@/components/Button'; // Server 版本(默认)
import { ClientButton } from '@/components/Button'; // Client 版本
模式 5:数据获取的 Suspense 边界
// app/dashboard/layout.tsx
export default function Layout({ children }: { children: React.ReactNode }) {
return (
<div>
<Sidebar />
<main>
<Suspense fallback={<PageSkeleton />}>
{children}
</Suspense>
</main>
</div>
);
}
// 任意子页面都可以 await,不必整体阻塞
性能优化清单
- [ ] 把所有数据获取移到 Server Component
- [ ] 用 Promise.all 并行获取
- [ ] 用 Suspense 流式渲染慢的部分
- [ ] 删除不必要的 'use client'
- [ ] 用 Server Actions 替代 API routes
- [ ] 用 next/dynamic 懒加载 Client Component
- [ ] 用 next/image 优化图片
- [ ] 用 React.cache() 优化重复请求
5 个常见坑
坑 1:Client Component 里 await 数据
'use client';
export default function Page() {
const data = await fetchData(); // ❌ Client Component 不能 await
}
坑 2:Server Component 里用 useState
export default async function Page() {
const [count, setCount] = useState(0); // ❌ Server 没有 hooks
}
坑 3:Client Component 嵌套 Server Component
'use client';
import { ServerComponent } from './Server'; // ❌ Client 不能 import Server
坑 4:忘记给 Server Action 加 'use server'
// app/actions.ts
export async function deleteProduct(id: string) { // ❌ 缺 'use server'
await db.products.delete(id);
}
坑 5:滥用 'use client'
很多团队"安全起见"全加 'use client',结果 bundle 反而更大。默认不加,需要交互才加。
我的看法
RSC 是前端架构的重要演进:
- 减少 JS bundle:性能提升立竿见影
- 简化数据流:不用 manage client state 缓存
- 更好的 SEO:服务端渲染变成默认
但迁移成本不低:
- 需要团队重新学习"边界"概念
- 需要重构现有 Client Component
- 需要重新考虑状态管理(部分状态可以放服务端)
我的建议:
- 新项目:直接用 App Router + RSC
- 旧项目:渐进式迁移,先把"只读"的页面转 RSC
- 状态复杂的页面:保留 Client Component,不必强转
参考
本文迁移示例基于真实电商项目,2026 年 Q2 实测数据。
📚 同主题文章
Next.js SEO 实战:从技术 SEO 到 GEO(生成式引擎优化)2026
2026 年 SEO 新规则:GEO(生成式引擎优化)让 ChatGPT / Perplexity / Claude 引用你的内容。本文 Next.js 16 SEO + GEO 完整指南,含 6 大策略 + 4 个实战。
Motion + 动画设计实战:现代 Web 交互动效完整指南 2026
Motion(原 Framer Motion)是 2026 年最流行的 React 动画库。本文从 0 到生产级交互动效,含 4 个实战项目 + 性能优化 + AI 动画 + 设计令牌。
shadcn/ui + 设计系统 2026:现代 Web 产品的 UI 实战
shadcn/ui 是 2026 年最火的前端组件库 + 设计系统方案。本文从 0 到完整设计系统,含 5 个真实项目 + 主题定制 + 组件库扩展 + A11y。