MDX嵌入Video标签触发Minified React错误#418求助
问题
使用rspress.js静态站点生成器编写MDX文档时,本地环境(localhost)中嵌入的短视频可正常显示,但部署到服务器后无法加载。Chrome开发者工具提示Minified React错误#418,核心原因是Hydration失败:服务端渲染的HTML与客户端DOM不匹配,将在客户端重新生成DOM树。
MDX代码示例
* **New link** (or edge). Click on the arrow button and then drag from one factor to another to link them. If you wish, you can have two links between a pair of factors: one for each direction. <video width={640} height={360} muted loop autoPlay playsInline> <source src={normalizeImagePath("/images/create-link-nodes.mp4")} type="video/mp4" /> </video>
注:
normalizeImagePath是rspress提供的路径处理函数,同文件内的<img>标签使用该函数可正常显示,路径问题可能性较低。
浏览器解析后的HTML
<li class="[&:not(:first-child)]:mt-2"> <p class="my-4 leading-7"><strong class="font-semibold">New link</strong> (or edge). Click on the arrow button and then drag from one factor to another to link them. If you wish, you can have two links between a pair of factors: one for each direction.</p> <video width="640" height="360" muted="" loop="" autoplay="" playsinline=""><source src="/doc/help/doc_build/images/create-link-nodes.mp4" type="video/mp4"/></video> </li>
问题根源与解决方法
根源分析
问题出在React服务端渲染(SSR)与客户端Hydration的属性匹配差异:
- 属性大小写不匹配:MDX中使用的React驼峰式属性(
autoPlay、playsInline),在服务端渲染时会被转换为HTML原生的小写属性(autoplay、playsinline),但客户端Hydration时会严格校验属性的大小写,导致不匹配触发错误。 - 布尔属性的渲染差异:React中的布尔属性(如
muted、loop)在服务端会被渲染为带空字符串的属性(muted=""),而客户端期望的是纯布尔属性形式,进一步加剧Hydration不匹配。
解决方案
方案1:统一使用HTML原生属性格式
将MDX中video标签的驼峰属性改为HTML原生的小写形式,布尔属性直接保留属性名即可:
* **New link** (or edge). Click on the arrow button and then drag from one factor to another to link them. If you wish, you can have two links between a pair of factors: one for each direction. <video width={640} height={360} muted loop autoplay playsinline> <source src={normalizeImagePath("/images/create-link-nodes.mp4")} type="video/mp4" /> </video>
方案2:客户端挂载后再渲染视频(绕过SSR校验)
如果方案1无效,可以通过React的useEffect钩子,等待客户端挂载完成后再渲染视频,避免服务端与客户端的属性校验冲突:
import { useEffect, useState } from 'react'; const VideoPlayer = ({ src, width, height }) => { const [isClient, setIsClient] = useState(false); useEffect(() => { setIsClient(true); }, []); if (!isClient) return null; return ( <video width={width} height={height} muted loop autoplay playsinline> <source src={normalizeImagePath(src)} type="video/mp4" /> </video> ); }; * **New link** (or edge). Click on the arrow button and then drag from one factor to another to link them. If you wish, you can have two links between a pair of factors: one for each direction. <VideoPlayer src="/images/create-link-nodes.mp4" width={640} height={360} />
内容的提问来源于stack exchange,提问作者Nigel
相关产品推荐
相关产品推荐

