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

Next.js服务端渲染页面中<video>标签导致hydration失败求助

Next.js SSR中video标签引发Hydration失败的原因及解决办法

原因分析

  • 服务器仅输出静态的video标签结构,但客户端浏览器加载后会自动为video元素添加播放状态属性、内部DOM节点等运行时内容,导致客户端DOM与服务端输出的HTML结构/状态不匹配,触发Hydration校验失败。
  • autoPlay、loop这类属性会让客户端浏览器立即执行播放逻辑,改变元素状态,而服务器无法模拟这些运行时行为,进一步放大了两端的DOM差异。
  • 错误提示提到的h2、section标签问题是Hydration失败后的连锁报错,实际根源是video标签的状态不匹配。

保留视频并维持SSR的解决办法

1. 动态渲染video标签(推荐)

让video标签仅在客户端渲染,避免服务端输出后与客户端状态冲突,有两种实现方式:

方式一:用useEffect控制渲染时机

import { useState, useEffect } from 'react';
import styles from './YourComponent.module.css';

export default function Home() {
  const [renderVideo, setRenderVideo] = useState(false);

  useEffect(() => {
    // 客户端组件挂载后再渲染视频
    setRenderVideo(true);
  }, []);

  return (
    <div>
      {/* 其他SSR渲染的页面内容 */}
      {renderVideo && (
        <video
          autoPlay
          preload="auto"
          loop
          muted
          className={styles.video}
        >
          <source src="/landing/video.webm" type="video/webm" />
        </video>
      )}
    </div>
  );
}

方式二:用dynamic导入禁用SSR的视频组件

先创建独立的视频组件VideoComponent.js:

import styles from './YourComponent.module.css';

export default function VideoComponent() {
  return (
    <video
      autoPlay
      preload="auto"
      loop
      muted
      className={styles.video}
    >
      <source src="/landing/video.webm" type="video/webm" />
    </video>
  );
}

然后在首页组件中导入该组件,禁用SSR:

import dynamic from 'next/dynamic';

const VideoComponent = dynamic(() => import('./VideoComponent'), {
  ssr: false,
  loading: () => <div>视频加载中...</div> // 可选添加加载占位
});

export default function Home() {
  return (
    <div>
      {/* 其他SSR渲染的页面内容 */}
      <VideoComponent />
    </div>
  );
}

2. 跳过局部Hydration校验(应急方案)

给video标签的父容器添加suppressHydrationWarning={true},跳过该区域的Hydration差异校验,但这种方式可能掩盖其他潜在问题,不推荐长期使用:

<div suppressHydrationWarning={true}>
  <video
    autoPlay
    preload="auto"
    loop
    muted
    className={styles.video}
  >
    <source src="/landing/video.webm" type="video/webm" />
  </video>
</div>

3. 调整video属性减少状态差异

移除autoPlay属性,改为客户端挂载后手动触发播放,避免客户端立即修改元素状态:

import { useRef, useEffect } from 'react';
import styles from './YourComponent.module.css';

export default function Home() {
  const videoRef = useRef(null);

  useEffect(() => {
    videoRef.current?.play();
  }, []);

  return (
    <video
      ref={videoRef}
      preload="auto"
      loop
      muted
      className={styles.video}
    >
      <source src="/landing/video.webm" type="video/webm" />
    </video>
  );
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 18:58:14