Next13中<Script/>更新html className的Hydration错误与深色模式闪烁问题
解决Tailwind暗黑模式闪烁与Hydration警告问题
一、彻底消除页面闪烁问题
用useEffect或afterInteractive脚本都会因执行时机滞后导致闪烁,最优解法是在_document.tsx(或_document.js)中添加同步内联脚本,让代码在页面DOM渲染前就读取localStorage并设置html的className:
// pages/_document.tsx import { Html, Head, Main, NextScript } from 'next/document' export default function Document() { return ( <Html> <Head /> <body> {/* 同步脚本,页面渲染前执行 */} <script dangerouslySetInnerHTML={{ __html: ` if (localStorage.theme === 'dark' || (!('theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches)) { document.documentElement.classList.add('dark') } else { document.documentElement.classList.remove('dark') } ` }} /> <Main /> <NextScript /> </body> </Html> ) }
该脚本会在浏览器解析页面内容前运行,直接为html标签加上dark类,从根源避免闪烁问题。
二、禁用特定元素的Hydration警告
若需保留原有实现并屏蔽Hydration警告,可直接在服务端与客户端内容可能不匹配的元素上添加suppressHydrationWarning属性:
// 在html根元素上添加 <Html suppressHydrationWarning> {/* ... */} </Html> // 或在具体不匹配的元素上添加 <div suppressHydrationWarning className={isDark ? 'dark' : ''}> {/* ... */} </div>
这个属性会告知Next.js忽略该元素的Hydration一致性检查,开发模式下就不会再弹出相关错误。需要注意的是,suppressHydrationWarning仅作用于单个元素,无法传递给子元素,需加在最外层存在不匹配的节点上。
另外,使用beforeInteractive脚本时出现开发模式Hydration错误,本质是服务端渲染的html无dark类,但客户端脚本提前添加导致DOM不匹配。上述_document内联脚本方案已从根源规避了这个问题——服务端渲染的html虽无dark类,但客户端脚本在DOM渲染前就完成了类的添加,不会触发Hydration不匹配。
内容的提问来源于stack exchange,提问作者Kacper
相关产品推荐
相关产品推荐

