说说 React 服务端渲染怎么做?原理是什么?
一、是什么
服务端渲染(Server-Side Rendering,SSR)是指将 React 组件在服务器端执行渲染,生成完整的 HTML 字符串发送到浏览器,浏览器接收后可以直接展示内容,然后再通过水合(Hydration)将 HTML 与客户端 JavaScript 绑定,使页面具备交互能力。
与传统的客户端渲染(CSR)对比:
二、基本原理与实现
核心 API
React 提供了专门的服务端渲染 API,位于 react-dom/server:
renderToString 基础用法
客户端水合(Hydration)
服务端输出的只是静态 HTML,需要在客户端进行水合以激活事件绑定和交互逻辑:
hydrateRoot 与 createRoot 的区别:
createRoot:从零开始创建 DOMhydrateRoot:复用服务端已有的 DOM 节点,仅附加事件监听器和状态管理
如果服务端和客户端渲染结果不一致,React 会发出水合不匹配(hydration mismatch)警告,并尝试修复。
三、React 18 流式渲染
React 18 引入了 renderToPipeableStream,支持流式 SSR,配合 Suspense 实现渐进式页面加载:
配合 Suspense 实现选择性水合
流式渲染的工作流程:
- 服务端首先发送 Shell 部分(Header + 两个 Suspense fallback)
- 当
MainContent数据就绪,服务端流式推送其 HTML 并替换 fallback Comments同理,独立于MainContent完成- 客户端进行选择性水合——用户交互的区域优先水合
这解决了传统 SSR 的 "全部等待" 问题:不需要所有数据都就绪才能开始发送 HTML。
四、SSR 的优势与挑战
优势
- SEO 友好:搜索引擎直接获取完整 HTML 内容
- 更快的 FCP:用户在 JS 加载前就能看到页面内容
- 可访问性:即使 JS 加载失败,核心内容依然可见
- 社交媒体分享:Open Graph 等 meta 标签在分享时可被正确解析
挑战与注意事项
主要挑战:
- 服务器负载增加:每个请求都需要渲染,CPU 密集
- 开发复杂度:需要处理服务端/客户端环境差异
- TTFB 可能增加:服务端渲染需要时间,首字节到达时间变长
- 状态同步:服务端获取的数据需要传递到客户端避免重复请求
- 第三方库兼容性:部分库依赖浏览器 API,在服务端无法使用
数据获取与状态同步
五、Next.js 中的 SSR
Next.js 是 React 官方推荐的 SSR 框架,极大简化了服务端渲染的配置:
App Router(Next.js 13+)
客户端组件
六、SSG、SSR、ISR 对比
七、React Server Components
React Server Components(RSC)是 React 18 引入的全新架构,与 SSR 互补但不等同:
RSC 让服务端组件的 JS 完全不进入客户端打包产物,显著减少了 bundle 体积。
八、总结
SSR 的核心价值在于改善首屏体验和 SEO,但也带来了架构复杂度。现代 React SSR 的演进方向:
- React 18 流式渲染:解决了传统 SSR 的 "全有或全无" 问题
- 选择性水合:优先水合用户正在交互的部分
- RSC:进一步减少客户端 JS 体积
- Next.js App Router:将 SSR、SSG、ISR、RSC 统一到一个直觉化的开发模型中
选型建议:
- 纯内部管理后台 → CSR 即可
- 需要 SEO 的内容型网站 → SSG 或 ISR
- 需要实时数据 + SEO → SSR
- 复杂应用追求极致性能 → RSC + 流式 SSR