4 个英文缩写

策略 全名 一句话
CSR Client-Side Rendering 浏览器拿空 HTML + JS bundle,JS 跑完才出内容
SSR Server-Side Rendering 服务器每次请求渲染 HTML 返回
SSG Static Site Generation 构建时一次性预渲染 HTML,请求时直接发文件
ISR Incremental Static Regen SSG + 后台按需更新(Next.js 的招牌)

CSR:经典 SPA

// Vite + React Router 的 index.html
<div id="root"></div>
<script src="/bundle.js"></script>

优点

  • 部署简单(任意 CDN 扔静态文件)
  • 切换路由无白屏
  • 后端只管 API

缺点

  • 首屏白
  • SEO 差(爬虫看到空 div)
  • 弱设备 / 弱网解析 JS 慢

适用

  • 内部工具 / 后台
  • 登录后看到的 dashboard
  • SEO 不重要

SSR:每次请求渲染

// Next.js Pages Router 老法
export async function getServerSideProps() {
  const data = await fetch(...);
  return { props: { data } };
}

App Router 新法:

// 默认每次请求渲染
export default async function Page() {
  const data = await fetch('https://api/...', { cache: 'no-store' });
  return <div>{data.x}</div>;
}

优点

  • 首屏直接出 HTML(快、SEO 友好)
  • 数据永远最新

缺点

  • 每次请求都要服务器算(CPU 成本)
  • 慢接口拖累 TTFB

适用

  • 内容随时变(个性化 dashboard、实时数据)
  • 必须最新(订单详情、库存)

SSG:构建时预渲染

// Next.js 15+:fetch 默认不缓存。要 SSG 必须显式 force-cache(或加 revalidate)
export default async function Page() {
  const posts = await fetch('https://api/posts', { cache: 'force-cache' }).then(r => r.json());
  return <PostList posts={posts} />;
}

// 或者整页声明
export const dynamic = 'force-static';

优点

  • 极快(HTML 已经在 CDN)
  • 0 服务器算力
  • 极便宜

缺点

  • 数据更新要重新构建
  • 大量页面构建慢(10w 篇博客构建 30 分钟)

适用

  • 博客 / 文档 / 营销页
  • 内容更新不频繁

ISR:SSG + 后台刷新

// 这条路由:构建时预渲染,但每 60 秒后台请求时重新生成
export default async function Page() {
  const data = await fetch('https://api/...', { next: { revalidate: 60 } });
  return ...;
}

或者基于事件按需更新:

// 在 Server Action 或 API 路由里
import { revalidatePath, revalidateTag } from 'next/cache';
revalidatePath('/posts/[id]', 'page');

优点:SSG 的速度 + SSR 的新鲜度 缺点:心智模型复杂、调试 cache 烦

适用:电商列表 / 价格 / 排行榜 / 半实时内容

混合:一个网站多种共存

首页 marketing       → SSG
博客文章详情         → SSG
登录后 dashboard     → CSR(或 SSR if SEO 需要)
产品列表(价格变)   → ISR
订单详情             → SSR(必须最新)
搜索结果             → CSR(用户行为驱动)

Next.js 让一个项目里不同路由用不同策略——你不用全押在一种上。

RSC 改变了什么

React Server Components不替代上面 4 种,它是上面 4 种的实现方式之一。Next.js 15+ 的默认是 SSR / 动态渲染,你需要显式 opt-in 静态:

  • cache: 'force-cache'export const dynamic = 'force-static' → SSG
  • cache: 'no-store'export const dynamic = 'force-dynamic'(默认) → SSR
  • next: { revalidate: N } → ISR
  • next: { tags: [...] } + revalidateTag() → 按需 ISR

RSC 真正的新东西是:部分组件在服务器、部分在客户端、bundle 更小

Hydration(水合)

SSR/SSG 的 HTML 到了浏览器,JS 还得跑一遍给 HTML 接事件——这叫 hydration。

如果服务器渲染的 HTML 和客户端首次 render 结果不一致,React 报警 "hydration mismatch"。常见原因:

function NavBar() {
  return <p>{new Date().toLocaleString()}</p>;   // 服务器和客户端时间不一样 → mismatch
}

修:

  • 把时间逻辑放进 useEffect(客户端跑)
  • 或用 <time suppressHydrationWarning>...</time>(白名单这一处)

选哪种?决策表

你的需求
SEO 重要 + 内容稳定 SSG
SEO 重要 + 内容半实时 ISR
SEO 重要 + 内容实时 / 个性化 SSR
SEO 不重要 + 内部工具 CSR
部分页 SEO 重要、部分不重要 混合(Next.js 默认就支持)

部署影响

  • CSR:纯静态托管(CDN / S3 / Pages)
  • SSG:同上
  • ISR:需要 Node / Edge 运行时(Vercel / 自建 Node 服务器)
  • SSR:同上

→ 下一篇 生产部署