You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React中Hydration是什么?求其工作原理及hydration error解决方法

React Hydration 工作原理及 hydration error 排查解决

一、Hydration 是什么?它的工作原理

Hydration(水合)是 React 服务端渲染(SSR)或静态站点生成(SSG)流程中的核心步骤,目的是把服务端输出的静态 HTML 转换成可交互的 React 应用,具体流程如下:

  • 第一步:服务端生成静态 HTML
    服务端会将 React 组件编译成完整的 HTML 字符串(比如 Next.js 中通过 getServerSideProps/getStaticProps 预取数据后渲染组件),然后把这个 HTML 发送给浏览器。此时用户看到的是静态页面,没有任何交互能力。

  • 第二步:浏览器加载并显示静态内容
    浏览器接收到 HTML 后会快速解析并渲染,用户能立刻看到页面内容,这也是 SSR/SSG 提升首屏体验的关键。

  • 第三步:React 客户端代码启动并对比 DOM
    浏览器加载完 React 客户端代码后,会生成对应的虚拟 DOM,然后和服务端输出的真实 DOM 结构做严格对比。

  • 第四步:完成 Hydration,激活交互
    当虚拟 DOM 和真实 DOM 完全匹配时,React 会给 DOM 元素绑定事件处理器,激活组件的状态管理逻辑,静态页面就变成了可交互的 React 应用。

核心原则:服务端输出的 HTML 结构必须和客户端首次渲染的虚拟 DOM 结构完全一致,否则就会触发 hydration error。

二、常见 hydration error 原因及解决方法

hydration error 的本质是「服务端 HTML」和「客户端首次渲染的 DOM」不匹配,以下是最常见的场景和解决方式:

1. 浏览器专属 API 在服务端被调用

服务端没有 window、document 等浏览器专属对象,如果组件在初始化阶段(比如 render 函数、useState 初始化、组件顶层代码)直接访问这些对象,会导致服务端和客户端渲染的内容不一致。

错误示例:

function Header() {
  // 服务端渲染时会报错,且客户端渲染的内容和服务端不一致
  const isMobile = window.innerWidth < 768;
  return <div>{isMobile ? '移动端导航' : '桌面端导航'}</div>;
}

解决方法:
把浏览器专属逻辑放到 useEffect 中,确保只在客户端 Hydration 完成后执行:

function Header() {
  const [isMobile, setIsMobile] = useState(false);

  useEffect(() => {
    setIsMobile(window.innerWidth < 768);
    // 可选:监听窗口大小变化
    const handleResize = () => setIsMobile(window.innerWidth < 768);
    window.addEventListener('resize', handleResize);
    return () => window.removeEventListener('resize', handleResize);
  }, []);

  return <div>{isMobile ? '移动端导航' : '桌面端导航'}</div>;
}

2. 服务端与客户端数据不一致

如果服务端渲染时使用的数据和客户端首次渲染时的数据不同,会直接导致 DOM 结构差异。比如服务端从数据库取到的用户信息,和客户端从本地缓存取到的不一致。

解决方法:

  • 确保服务端和客户端使用同一数据源获取数据;
  • 在 SSR/SSG 流程中,将服务端获取的数据通过 props 传递给客户端,避免客户端重复获取不同数据;
  • 如果必须在客户端获取数据,在数据加载完成前,渲染和服务端一致的占位符(比如 loading 骨架屏)。

3. 条件渲染逻辑不一致

服务端和客户端的条件判断逻辑不同,会导致渲染的 DOM 结构不一样。比如服务端判断用户登录状态的逻辑依赖后端接口,而客户端依赖 localStorage,两者结果不同。

解决方法:

  • 统一服务端和客户端的条件判断逻辑;
  • 如果条件依赖客户端专属状态(比如 localStorage、sessionStorage),先在服务端渲染默认状态的内容,再通过 useEffect 在 Hydration 完成后更新组件状态:
function UserProfile() {
  const [user, setUser] = useState(null);

  useEffect(() => {
    // 客户端从 localStorage 获取用户信息
    const savedUser = localStorage.getItem('user');
    if (savedUser) setUser(JSON.parse(savedUser));
  }, []);

  // 服务端和客户端首次渲染都显示占位符
  if (!user) return <div>加载中...</div>;
  return <div>欢迎,{user.name}</div>;
}

4. 第三方组件不支持 SSR

部分第三方 UI 组件没有做 SSR 适配,服务端渲染时输出的 HTML 和客户端渲染的不一致。

解决方法:

  • 查看组件文档,确认是否支持 SSR,按照文档配置;
  • 在 Next.js 等框架中,用动态导入并禁用 SSR,让组件只在客户端渲染:
import dynamic from 'next/dynamic';

const NonSSRComponent = dynamic(() => import('../components/NonSSRComponent'), {
  ssr: false,
  loading: () => <div>加载中...</div>
});

5. DOM 属性或标签名不匹配

比如服务端输出的 HTML 中用了错误的属性名(比如手动写 class 而非 React 标准的 className),或者标签名大小写不一致(比如服务端输出 <div>,客户端渲染 <DIV>),都会导致对比失败。

解决方法:

  • 始终使用 React 标准的属性名(比如 className 代替 class,htmlFor 代替 for);
  • 确保标签名统一使用小写,避免大小写差异。

调试技巧

浏览器控制台的 hydration error 信息会明确指出不匹配的 DOM 元素位置,根据提示定位到对应的组件,逐一排查上述场景即可。

内容的提问来源于stack exchange,提问作者himanshu_942

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 21:14:57