什么是 SSR(服务端渲染)?React 中如何实现?
CSR vs SSR vs SSG
| 方式 | 说明 | 优势 | 劣势 |
|---|---|---|---|
| CSR | 客户端渲染 | 交互流畅 | 首屏慢、SEO 差 |
| SSR | 服务端渲染 | 首屏快、SEO 好 | 服务器负载高 |
| SSG | 静态生成 | 最快、CDN 友好 | 内容固定 |
| ISR | 增量静态生成 | 兼顾速度和动态性 | 配置复杂 |
React SSR 基本流程
1. 服务器接收请求
2. 执行 React 组件 → 生成 HTML 字符串
3. 返回 HTML(包含初始数据)
4. 浏览器显示 HTML(首屏可见)
5. 浏览器加载 JS
6. Hydration:JS 接管页面,变成可交互原生 React SSR
// server.js
import { renderToString } from 'react-dom/server'
app.get('/', (req, res) => {
const data = await fetchData()
const html = renderToString(
<App initialData={data} />
)
res.send(`
<html>
<body>
<div id="root">${html}</div>
<script>window.__INITIAL_DATA__ = ${JSON.stringify(data)}</script>
<script src="/client.js"></script>
</body>
</html>
`)
})Next.js(推荐方案)
// App Router (Next.js 13+)
// app/page.js
export default async function Page() {
const data = await fetch('https://api.example.com/data')
const json = await data.json()
return <div>{json.title}</div>
}
// 动态路由
// app/posts/[id]/page.js
export default async function Post({ params }) {
const post = await getPost(params.id)
return <article>{post.content}</article>
}
// 客户端组件
'use client'
import { useState } from 'react'
export default function Counter() {
const [count, setCount] = useState(0)
return <button onClick={() => setCount(c => c + 1)}>{count}</button>
}Hydration(水合)
// 客户端代码
import { hydrateRoot } from 'react-dom/client'
// 不是 createRoot(会重新渲染),而是 hydrateRoot(复用 DOM)
hydrateRoot(document.getElementById('root'), <App initialData={window.__INITIAL_DATA__} />)Hydration Mismatch
如果服务端和客户端渲染结果不一致,React 会警告并重新渲染:
// ❌ 服务端和客户端可能不同
function Time() {
return <div>{new Date().toLocaleTimeString()}</div>
}
// ✅ 先渲染占位,客户端挂载后再显示
function Time() {
const [time, setTime] = useState(null)
useEffect(() => {
setTime(new Date().toLocaleTimeString())
}, [])
return <div>{time || 'Loading...'}</div>
}何时用 SSR
- ✅ 内容型网站(博客、电商、新闻)→ SEO 重要
- ✅ 首屏性能要求高的页面
- ❌ 后台管理系统 → CSR 足够
- ❌ 高交互应用(如编辑器)→ CSR 更合适
React Server Components(RSC)
React 18 引入的服务端组件:
- 在服务端渲染,不发送到客户端
- 可以直接访问数据库/文件系统
- 0 KB 客户端 JS 体积
- Next.js App Router 默认就是 RSC