news 2026/6/24 9:19:21

为什么 SSR 一定会有 hydration mismatch?

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
为什么 SSR 一定会有 hydration mismatch?

一、先把问题还原到最本质

SSR 做了两件事:

  1. 服务端生成 HTML
  2. 客户端接管(Hydration)

Hydration 的本质是:

在不重建 DOM 的情况


二、关键矛盾:同一份代码,在两个环境执行

这是问题的根源。

SSR 架构本质是:

同一套组件逻辑 在两个环境执行: - Node(服务端) - Browser(客户端)

问题在于:

这两个环境永远不可能完全一致


三、用一个最简单的例子说明

<span>{new Date().getMilliseconds()}</span>

服务端输出:

<span>123</span>

客户端执行:

<span>167</span>

结果:

不一致 → mismatch (Vite-plugin-ssr)
所以推导出一个结论:只要渲染依赖“运行时”,就必然存在不一致的可能


四、为什么“不一致”是必然的

从几个维度拆开看:


1. 时间是不一致的

Date.now() new Date()
  • 服务端时间 ≠ 客户端时间
  • 网络延迟会放大差异

结论:

只要用时间,就有 mismatch 风险 (Vite-plugin-ssr)


2. 环境是不一致的

服务端没有:

window document localStorage

客户端有,典型代码:

if (typeof window !== 'undefined') { // client logic }

结果:

  • 服务端渲染 A
  • 客户端渲染 B

直接 mismatch


3. 状态是不一致的

例如:

if (localStorage.getItem('token')) { return <Home /> } else { return <Login /> }

服务端:

  • 没有 localStorage → Login

客户端:

  • 有 token → Home

结果:

DOM 完全不同


4. 随机性是不一致的

Math.random() uuid()

服务端生成一套
客户端再生成一套

结论:

不可能一致


5. 执行顺序是不一致的

例如:

  • async 数据
  • 并发渲染
  • 不稳定 ID 生成

再次重复一开始提到的前提:SSR 本质是“重复计算”,而重复计算无法保证一致性


五、为什么框架“必须要求一致”?

问题来了:

为什么一定要一致?

因为 Hydration 的优化前提是:

复用已有 DOM 而不是重新创建

如果不一致:

框架只能:

  1. 丢弃 DOM
  2. 重新渲染

这会导致:

  • 闪屏
  • 性能下降
  • 交互延迟 (原理详解)

一个更本质的矛盾

SSR 想要:

提前生成 HTML(提高首屏)

但 Hydration 需要:

再执行一遍渲染逻辑

这本身就是:

一次“重复执行系统”

而所有重复执行系统都有一个问题:

一致性无法保证


六、工程上怎么“缓解”,但不是“解决”(mismatch 只能减少,无法彻底消灭)

常见手段:

1. 保证初始数据一致

// server 计算 const data = fetch() // 注入 HTML window.__INITIAL_DATA__ = data

2. 延迟客户端逻辑

useEffect(() => { // client only }, [])

3. 避免不确定性

不要在 render 中用:

  • Date
  • Math.random
  • 浏览器 API

4. 架构层优化

例如:

  • Islands Architecture
  • Partial Hydration

本质是:

减少需要 hydration 的范围


七、讨论一下 Islands:为什么这个架构本质是在“逃避 hydration”

先看传统 SSR 流程:

Server Render HTML ↓ Browser 接收 HTML ↓ 整页 Hydration ↓ 页面可交互

问题在于:

页面里很多内容其实根本不需要交互。

例如一个电商详情页:

  • 商品标题
  • 商品描述
  • banner
  • 评论文本
  • footer

这些内容:

  • 需要 SEO
  • 需要首屏展示
  • 但不需要 JS 接管

然而传统 SSR 会做什么?

即使这些内容完全静态,也要执行 hydration。

也就是说:

静态内容 + 动态内容 全部进入 hydration

这就带来两个问题:

1. 不必要的 JS 执行

例如页面结构:

<div> Header ProductInfo Comments BuyButton Footer </div>

真正需要交互的可能只有:

BuyButton

但传统 hydration:

Header hydrate ProductInfo hydrate Comments hydrate BuyButton hydrate Footer hydrate

本质上:

为了一个按钮,整页都要重复执行一遍。

这很浪费。


2. mismatch 风险被放大

前面说过:

hydration 本质是重复计算

那只要重复计算范围越大:

  • 时间差异
  • 环境差异
  • 状态差异

都会扩大。

整页 hydration 意味着:

整页都有 mismatch 风险。


Islands 的思路:不要整页 hydration

Islands 架构把页面拆成:

  • Static HTML
  • Interactive Islands

例如:

<Header /> <ProductInfo /> <BuyButton client:load /> <Footer />

只有:

BuyButton

需要客户端接管。

其余部分:

  • 只保留 HTML
  • 永不 hydration

流程变成:

Server Render HTML ↓ 静态部分直接展示 ↓ 仅局部组件 hydration

本质变化

传统 SSR:

HTML 先渲染,JS 再接管整页

Islands:

HTML 默认静态,只有少数区域需要 JS

所以它的核心思想不是:

“怎么更高效地 hydration”

而是:

尽量少 hydration,甚至不 hydration

这就是为什么说:

Islands 本质是在逃避 hydration。

不是因为 hydration 做得不好,而是因为:

hydration 天然昂贵且天然存在一致性问题。

既然如此,最好的办法不是优化它,而是减少它。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/24 9:18:38

[Android] AI视频生成神器-免费无限次数AI成片

[Android] AI视频生成神器-免费无限次数AI成片 链接&#xff1a;https://pan.xunlei.com/s/VOvnKz0MC5Jc2pPxW0TsfB9JA1?pwd9pir# 这款AI视频生成工具是超实用免费创作软件&#xff0c;支持文字生成视频、图片转动态短片&#xff0c;全程免费使用&#xff0c;AI生成次数无任…

作者头像 李华
网站建设 2026/6/24 9:18:28

2026年小程序商城需要多少钱呢

2026年小程序商城需要多少钱呢问小程序商城需要多少钱&#xff0c;最怕得到一个过于干脆的数字。商城不是一张展示页&#xff0c;钱花在哪里&#xff0c;要看商品数量、支付链路、会员体系、营销活动、后台权限和后续维护。预算只有1500元和预算8000元&#xff0c;能做的不是同…

作者头像 李华
网站建设 2026/6/24 9:17:33

【JavaWeb】CSS基础入门 —— 让你的网页美起来

一、CSS是什么&#xff1f; CSS&#xff08;Cascading Style Sheets&#xff09;&#xff0c;即层叠样式表&#xff0c;是一种用于描述HTML文档外观和格式的样式语言。 HTML与CSS的关系 技术角色比喻HTML网页内容的载体人的骨架CSS网页样式的表现人的衣服、妆容JavaScript网页…

作者头像 李华
网站建设 2026/6/24 9:17:16

junit5->assertAll()

当测试中某个断言失败时&#xff0c;JUnit 会停止执行后续断言。如果您希望确保所有断言都得到检查&#xff0c;而不管个别断言是否失败&#xff0c;请使用 assertAll() 对分组断言进行处理。 使用分组断言&#xff0c;即使断言失败&#xff0c;所有断言也会执行&#xff0c;并…

作者头像 李华
网站建设 2026/6/24 9:15:08

损失函数 的 硬截断 和 平滑衰减

损失函数 的 硬截断 和 平滑衰减 flyfish 在逐样本损失计算完成、取平均之前&#xff0c;对损失过高的样本做权重压制&#xff0c;不删除样本&#xff0c;只削弱它们对梯度的贡献&#xff0c;属于软降权——既保留了样本的监督信号&#xff0c;又避免极端难样本/疑似错标样本带…

作者头像 李华
网站建设 2026/6/24 9:13:06

5分钟快速上手Penpot:开源设计平台团队协作实战指南

5分钟快速上手Penpot&#xff1a;开源设计平台团队协作实战指南 【免费下载链接】penpot Penpot: The open-source design tool for design and code collaboration 项目地址: https://gitcode.com/GitHub_Trending/pe/penpot 你是否正在寻找一款既专业又灵活的设计工具…

作者头像 李华