React Hydration 是什么?Next.js 水合不一致报错怎么解决?
下面是一段教学用的模拟面试。
🧑💻 面试官:服务端已经输出了 HTML,为什么 React 还要做 Hydration?
🙋♂️ 我:HTML 先让用户看到页面,Hydration 再让页面能响应点击和状态更新。
🧑💻 面试官:服务端显示“请登录”,浏览器读到本地登录状态,第一次就显示用户名,可以吗?
🙋♂️ 我:看起来只是更新内容,但两边第一次渲染已经不一致了。
🧑💻 面试官:那我把报错压下去就行吗?页面上一个按钮还能点,是不是就说明没有问题?
水合排错要先对齐两次“第一次”:服务端生成的内容,和浏览器准备接管它时生成的内容。
面试速答(60 秒版)
Hydration 可以理解为 React 接管服务端提前生成的页面。HTML 负责先展示内容,浏览器里的 React 再把这些内容和组件逻辑对应起来,让事件与状态更新正常工作。
因此,服务端输出和客户端首次渲染需要保持一致。时间、随机数、本地存储、浏览器尺寸,以及不合法的 HTML 嵌套,都可能让两边得到不同结果。
排查时,我会先看报错指向的组件,再比较服务端结果和客户端第一次使用的数据。如果内容来自浏览器,就让首次渲染保留一个一致的默认值,接管完成后再更新;如果是服务端已经知道的数据,就把同一份初始数据传给客户端。
关闭局部 SSR 和压制警告都有适用范围,不能用它们掩盖整页的数据不一致。修完以后,还要检查交互和页面跳动,不能只看警告是否消失。

知识点详解:React 接管页面时,为什么要求内容对得上?
已经有 HTML,客户端还要做什么?
假设用户打开商品详情页。服务器根据商品数据生成标题、价格和购买按钮,浏览器收到 HTML 后,可以先把它们显示出来。
但这个按钮对应哪个组件、点击时执行什么逻辑、加入购物车后更新哪个状态,仍需要客户端 JavaScript 来处理。React 会根据相同的组件和初始数据构建客户端视图,再接管已有的 DOM。
所以,SSR 解决的是尽早展示内容,Hydration 解决的是把这份内容接入客户端组件系统。并不是把服务端页面毫无成本地“变活”,浏览器仍然需要下载和执行相关代码。
为什么读一个 localStorage 就会出问题?
服务端没有当前浏览器的 localStorage。假设服务器渲染的是“请登录”,客户端组件一开始读取本地用户信息,直接返回“欢迎,Sunday”。
两边看到的输入不同,第一次生成的内容也不同。React 接管时就找不到预期的一致结果。
比较稳妥的方式是:服务器和客户端首次都展示“正在确认登录状态”,接管完成后再读取浏览器信息,更新为用户名。这个默认状态要能被用户接受,还要避免布局突然挤开。
如果登录信息本来就在服务端可读取的安全会话里,也可以由服务器提供一致的初始结果,不一定非要等客户端再查一次。

时间和随机数,应该怎么处理?
假设组件每次渲染都生成当前时间。服务器执行时是 10:00:00,客户端执行时是 10:00:01,两份文本自然不一样。两边时区不同,也可能把同一个时间戳显示成不同日期。
如果这个时间属于页面数据,就固定初始时间戳和展示规则,并把它传给客户端。如果本来就是“浏览器当前时间”,就先展示统一占位,等接管以后更新。
随机编号也一样。需要稳定的组件标识时,使用框架提供的合适机制,别在渲染里临时生成随机值。不过稳定编号不能替代列表中来自业务数据的稳定 key。
数据相同,为什么还会报错?
还要看浏览器实际解析出了什么 DOM。
例如把块级内容错误地放进某些标签里,浏览器可能在 React 接管前就修正结构。服务器输出的字符串看似没问题,最终 DOM 却不是组件预想的层级。
浏览器扩展修改页面、边缘服务改写 HTML,也可能造成差异。因此排查顺序可以是:先定位组件,再核对初始数据和环境,最后检查 HTML 结构与外部改写。Next.js 官方也列出了这些常见原因,见 水合不一致排错文档。
什么时候可以关闭 SSR 或压制警告?
只依赖浏览器环境的局部组件,可以按框架支持的方式延后加载或禁用它的 SSR。例如必须操作浏览器设备能力的小部件,没必要硬让服务器生成它的完整界面。
但商品标题、正文这类重要内容如果全部改为客户端才加载,就会影响首屏体验,也可能增加搜索引擎理解内容的成本。技术选择要按组件职责来做。
压制水合警告则是局部例外的出口,适合确实无法保持一致、且差异已经理解清楚的内容。它不是修复按钮,也不保证所有不一致内容都会被正确更新。不要把它加到根节点以后,就宣布整站解决了。
面试官继续追问
改成 useEffect,就一定没有问题了吗?
它能把某些浏览器读取延后到接管以后,但读取结果仍要正确,组件也需要处理加载、失败和卸载。还有首屏占位与布局变化。不能把所有取数都搬进去来回避数据设计。
使用服务端组件,就不需要 Hydration 了吗?
服务端组件本身的执行位置和客户端组件不同,但页面里的客户端交互组件仍然需要接入浏览器运行。不能把“部分组件只在服务器执行”理解成“整页不再需要客户端接管”。
面试里怎么证明你真的排过这类问题?
说明两边第一次渲染分别读了什么、具体是哪项输入不同,以及你怎样让它们先一致再更新。比只说“用了 useEffect”更能体现理解。
面试速记卡
- SSR 先展示内容,Hydration 接管已有内容与交互。
- 对齐服务端结果和客户端首次渲染。
- 时间、随机数、浏览器数据和 HTML 结构都要检查。
- 浏览器专属信息可以在接管后更新。
- 局部禁用 SSR 与压制警告,都不能代替根因修复。
公司面试真题
这道题暂未收录可核验的公司真题来源。你可以先阅读本文解析,或浏览已收录的公司面试真题。
浏览公司面试真题 →