荆门市网站建设_网站建设公司_在线客服_seo优化
2026/1/16 22:27:23 网站建设 项目流程

目录

  • 前言
  • 一、React SSR 的概念
  • 二、React SSR 的核心原理
    • 1、服务端渲染 React 组件
    • 2、将 HTML 注入模板返回给浏览器
    • 3、客户端 hydration
  • 三、React SSR 的典型流程
    • 1、完整 React SSR 渲染流程
    • 2、面试必会:简述 React SSR 渲染流程(⭐️⭐️⭐️)
  • 四、React SSR 的数据获取方案(重点 & 难点)
    • 1、获取数据
      • (1)、方式一:在生命周期中获取(不推荐)
      • (2)、方式二:服务端数据预取(React 官方推荐)(⭐️⭐️⭐️⭐️⭐️)
        • ①、自定义静态方法获取 SSR 数据
    • 2、数据注入模板(⭐️⭐️⭐️⭐️⭐️)
  • 五、React SSR 的关键 API
  • 六、React SSR + React Router
  • 七、React SSR 的常用框架
    • 1、Next.js(绝对主流)
    • 2、其他方案
  • 八、React SSR 架构拆分(工程级)
  • 九、React SSR 的性能优化
    • 1、流式渲染
    • 2、缓存
      • (1)、静态资源缓存
      • (2)、服务端缓存
    • 3、减少 hydration 成本
  • 十、React SSR 实战要点
  • 十一、React SSR 的常见坑(非常重要)
    • 1、hydration mismatch
    • 2、直接访问浏览器 API
    • 3、useLayoutEffect 警告
    • 4、样式闪烁(FOUC)
  • 十二、SSR 与 CSR、SSG 的全面对比

前言

学习 React SSR 可与 Vue 之服务端渲染(SSR)对比学习(效率更高),虽然 Vue 和 React 框架不同,但 SSR 原理都是相通的。

一、React SSR 的概念

React SSR(Server-Side Rendering) 指的是:

  • 在**服务端(Node.js)**运行 React 组件,将其渲染成 完整 HTML 返回给浏览器,然后在客户端执行 hydration,让静态 HTML 变成可交互的 React 应用。
  • 简而言之:React SSR = 服务端先渲染页面结构,客户端再“接管”它

SSR(服务端渲染)对比 CSR(客户端渲染):

特性CSRSSR
HTML 初始内容空或 minimal shell完整 HTML 内容
首屏渲染时间较慢(需下载 JS 再渲染)较快(HTML 已在服务端生成)
SEO 支持较差较好(搜索引擎爬虫可直接抓取 HTML)
数据获取客户端 fetch服务端 fetch 或客户端 fetch
交互完全由客户端控制初次渲染由服务端生成,交互由客户端接管(hydration)

二、React SSR 的核心原理

React SSR 的核心在于 同一套 React 组件,在两个环境中执行:

环境职责
Node.js渲染 HTML
Browser绑定事件 + 管理状态

核心机制(render + hydrate)——在服务端调用 React 组件生成 HTML 字符串:

  • 服务端渲染 React 组件
  • 将 HTML 注入模板返回给浏览器
  • 客户端 hydration

1、服务端渲染 React 组件

import{renderToString}from'react-dom/server';importAppfrom'./App';consthtml=renderToString(<App/>);

2、将 HTML 注入模板返回给浏览器

consttemplate=`<html> <head><title>SSR Demo</title></head> <body> <div id="root">${html}</div> <script src="/bundle.js"></script> </body> </html>`;res.send(template);

3、客户端 hydration

import{hydrateRoot}from'react-dom/client';importAppfrom'./App';hydrateRoot(document.getElementById('root'),<App/>);

三、React SSR 的典型流程

1、完整 React SSR 渲染流程

浏览器请求URL↓ Node 服务接收请求 ↓ 创建 React 应用实例 ↓ 服务端路由匹配(StaticRouter) ↓ 服务端数据预取 ↓ renderToString/renderToPipeableStream ↓ 生成HTML↓ 注入模板+初始数据 ↓ 返回浏览器 ↓ 浏览器展示首屏 ↓ 客户端下载JS↓ hydrate(React 接管DOM) ↓ 后续进入SPA模式

⚠️ SSR 只负责首屏,之后就是纯 SPA

2、面试必会:简述 React SSR 渲染流程(⭐️⭐️⭐️)

  • 客户端请求 URL
  • 服务端根据 URL 渲染 React 组件生成 HTML
  • 服务端返回完整 HTML 给浏览器
  • 浏览器渲染 HTML, 展示首屏(HTML 即可)
  • React 客户端 JS 下载并执行 hydrate,接管页面交互(进入 SPA)
  • 后续操作可以通过客户端路由(如 React Router)处理,无需再回服务端渲染

四、React SSR 的数据获取方案(重点 & 难点)

在 SSR 场景下,页面在服务端渲染时就需要完成 数据获取和模板渲染,因此有几个核心问题:

  • 服务端渲染时需要数据:普通 React SPA 组件通常在 useEffect 或 componentDidMount 中获取数据,但 SSR 时这些生命周期不执行。
  • 服务端获取的数据如何注入 HTML:生成的 HTML 需要包含渲染所需数据,确保客户端 Hydration 后页面状态一致。
  • 客户端与服务端数据一致性:避免 Hydration 警告或重复请求。
方面重点难点
数据获取组件静态方法(fetchData/getInitialProps路由匹配组件层级深,如何保证所有异步请求完成
数据注入服务端渲染完成后,将初始状态注入 HTML数据序列化性能和安全(XSS 防护)
客户端复用Hydration 直接使用注入状态防止重复请求或状态不一致
异步依赖处理多组件并行/串行请求异步请求顺序和依赖管理
错误处理异步请求失败 → 返回 500 或 fallback如何优雅降级,不阻塞 SSR

1、获取数据

(1)、方式一:在生命周期中获取(不推荐)

方法:在 componentDidMount 或 useEffect 中请求数据

问题:

  • 服务端渲染不会执行这些生命周期
  • 初始 HTML 渲染时没有数据 → 页面空白 → SEO 不友好

结论:无法解决 SSR 数据预取问题,只适合客户端补数据。

(2)、方式二:服务端数据预取(React 官方推荐)(⭐️⭐️⭐️⭐️⭐️)

在 React SSR 中,通常做法分以下四步走:

  1. 组件提供静态数据获取接口
    • React 生态中常用:getInitialProps(Next.js)或“自定义静态方法”——例如 Component.fetchData(store, params)
  2. 服务端统一收集组件数据
    • 在服务端渲染前,遍历匹配的路由组件,执行所有数据请求
  3. 等待所有 Promise 完成后渲染
    • 渲染 HTML 时数据已准备好
  4. 注入数据到模板
    • 在 <script> 标签中注入初始数据,客户端 Hydration 时复用
①、自定义静态方法获取 SSR 数据
// React 组件functionPost({post}){return<div>{post.title}</div>;}// 静态方法获取数据(重要)Post.fetchData=(params)=>fetch(`/api/posts/${params.id}`).then(res=>res.json());// 服务端渲染asyncfunctionrender(url){constmatchedComponents=matchRoutes(routes,url).map(c=>c.component);constpromises=matchedComponents.filter(c=>c.fetchData).map(c=>c.fetchData({id:123}));constdata=awaitPromise.all(promises);// 将数据注入模板consthtml=ReactDOMServer.renderToString(<App initialData={data}/>);return`<div id="root">${html}</div> <script>window.__INITIAL_DATA__ =${JSON.stringify(data)}</script>`;}

核心点:服务端统一收集数据 → 渲染 HTML → 注入模板 → 客户端 Hydration

另外,在 SSR 中,组件通常需要服务端数据(API 数据):

  • 在服务端 fetch 数据
  • 客户端再 fetch 数据:
    • 优点:逻辑统一
    • 缺点:首屏可能白屏或闪烁

2、数据注入模板(⭐️⭐️⭐️⭐️⭐️)

注入模板主要目的是:

  • 服务端渲染 HTML 时直接使用数据
  • 客户端 Hydration 时复用数据,避免重复请求
<divid="root">${html}</div><script>window.__INITIAL_DATA__={...}<!--服务端注入--></script>

客户端使用:

constinitialData=window.__INITIAL_DATA__;constroot=document.getElementById('root');ReactDOM.hydrate(<App initialData={initialData}/>,root);

重点:保证服务端和客户端的数据一致,避免 Hydration 报错或二次请求

五、React SSR 的关键 API

API作用备注
renderToString服务端生成 HTML 字符串不包含事件绑定
renderToStaticMarkup服务端生成静态 HTML,无额外 React 属性SEO 优化,减少额外属性
hydrateRoot客户端接管服务端渲染的 HTMLReact 18+ 推荐用法
Suspense服务器端支持异步组件React 18 SSR 支持并发模式
renderToPipeableStreamReact 18 新增 SSR 流式渲染支持首屏更快渲染和可中断流

React 18 引入了流式 SSR,使得 首屏渲染速度 和 时间到交互(TTI) 更优秀。

六、React SSR + React Router

React Router v6 支持 SSR。

服务端:

import{StaticRouter}from'react-router-dom/server'<StaticRouter location={req.url}><App/></StaticRouter>

客户端:

import{BrowserRouter}from'react-router-dom'
环境Router
服务端StaticRouter
客户端BrowserRouter

七、React SSR 的常用框架

1、Next.js(绝对主流)

  • React 官方推荐
  • 内置:
    • SSR / SSG / ISR
    • 路由
    • 数据获取
    • SEO
    • Edge SSR
exportdefaultfunctionPage({data}){}

2、其他方案

框架特点
Remix数据优先
Razzle零配置
自建灵活但复杂

八、React SSR 架构拆分(工程级)

标准三入口结构:

src/├── App.tsx ├── entry-client.tsx └── entry-server.tsx

entry-server.tsx“:

consthtml=renderToString(<StaticRouter location={url}><App/></StaticRouter>)

entry-client.tsx:

hydrateRoot(document.getElementById('root'),<BrowserRouter><App/></BrowserRouter>)

九、React SSR 的性能优化

1、流式渲染

  • renderToPipeableStream 支持边渲染边发送 HTML
  • 可配合 Node.js res.write 实现更快首屏

renderToPipeableStream 流式渲染:

renderToPipeableStream(<App/>,{onShellReady(){stream.pipe(res)}})

2、缓存

(1)、静态资源缓存

  • SSR HTML 可做短期缓存
  • 静态 JS/CSS 可 CDN 缓存

(2)、服务端缓存

  • 页面渲染结果可缓存到 Redis 或内存,减少重复渲染开销

3、减少 hydration 成本

  • 避免不必要的状态
  • 合理拆 Suspense 边界

十、React SSR 实战要点

  • 每个请求必须是新 React 树
  • 服务端与客户端代码必须一致
  • 数据必须在 render 前准备好
  • 状态必须注入给客户端
  • 优先使用框架(Next.js)
  • SSR 只做首屏

十一、React SSR 的常见坑(非常重要)

1、hydration mismatch

❌ 错误再现:

Math.random()Date.now()

✔ 正确:

useEffect(()=>setTime(Date.now()),[])

2、直接访问浏览器 API

SSR 阶段只负责“算 HTML 字符串”,不是“跑页面”。

❌ 下面这些 API 在 React SSR 中「绝对不能直接用」:

window document localStorage

✅ 标准写法(必须牢记)

if(typeofwindow!=='undefined'){// 浏览器环境}

✅ 或者 放进 useEffect(推荐),例如:

useEffect(()=>{consttoken=localStorage.getItem('token')},[])

useEffect 永远不会在 SSR 执行。

3、useLayoutEffect 警告

useLayoutEffect → SSR 下会报警。

✔ 替代:

useEffect

4、样式闪烁(FOUC)

  • CSS 未提前注入
  • Next.js / CSS-in-JS 需配置 SSR

十二、SSR 与 CSR、SSG 的全面对比

对比维度CSR(客户端渲染)SSR(服务端渲染)SSG(静态站点生成)
渲染发生位置浏览器执行 JS 渲染服务器实时渲染 HTML构建阶段预生成 HTML
渲染时机页面加载后由 JS 渲染每次请求动态生成构建时一次性生成
首屏速度🐢 最慢(JS 执行后才出内容)👍 快(服务器已渲染)🚀 最快(CDN 直接返回 HTML)
SEO 效果⭐(较差,依赖 JS)⭐⭐⭐⭐(完美)⭐⭐⭐⭐(完美)
页面动态能力⭐⭐⭐(前端自由拉 API)⭐⭐⭐⭐(实时内容)⭐(内容固定,需重构建或 ISR)
服务器压力0(仅 API 压力)高(每次访问都需渲染)0(纯静态资源)
部署成本低(静态资源即可)高(需要 Node 服务)超低(CDN 即可)
可扩展性⭐⭐⭐⭐(静态资源无限扩展)⭐⭐(依赖服务器扩容)⭐⭐⭐⭐(CDN 无限扩展)
用户交互体验⭐⭐⭐⭐(SPA 最强体验)中等中等
工程复杂度高(所有逻辑在前端)简单
构建速度慢(页面越多越慢)
适合项目类型工具型 WebApp、后台系统电商、新闻、动态内容 + SEO博客、文档、官网
典型场景SaaS、仪表盘、在线编辑器商品页、新闻页、用户中心内容稳定、偶尔更新的网站
代表框架与模式React/Vue SPA + fetch API1、Next.js -getServerSideProps
2、Nuxt.js -asyncDatad
1、Next.jsgetStaticProps
2、Nuxt.js -asyncData
优点总结强交互、低成本、高灵活度首屏快、SEO 强、动态内容强极快、极便宜、SEO 佳、无服务器
缺点总结首屏慢、SEO 差成本高、服务器压力大不适合经常变化的内容

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询