Next.jsのHydration Errorが起きる可能性があるものを包括的にリストアップします。
window.innerWidth / window.innerHeightwindow.outerWidth / window.outerHeightwindow.scrollX / window.scrollYwindow.pageXOffset / window.pageYOffsetwindow.screen.width / window.screen.heightwindow.screen.availWidth / window.screen.availHeightwindow.devicePixelRatiowindow.location.* (href, pathname, search, hash等)window.history.*window.navigator.* (userAgent, language, onLine等)document.documentElement.clientWidth/clientHeightdocument.body.*document.cookiedocument.referrerdocument.getElementById() などのDOM参照localStorage.getItem()sessionStorage.getItem()indexedDBwindow.matchMedia('(prefers-color-scheme: dark)')window.matchMedia('(min-width: 768px)')navigator.geolocationnavigator.mediaDevicesnavigator.bluetoothnavigator.clipboardnavigator.credentialsNotification APIIntersectionObserverResizeObserverMutationObserverPerformanceObserverrequestAnimationFramerequestIdleCallbacknew Date() (現在時刻)Date.now()performance.now()Intl.DateTimeFormatの結果)new Date().getTimezoneOffset()Math.random()crypto.randomUUID()crypto.getRandomValues()getComputedStyle()element.offsetWidth/offsetHeightelement.clientWidth/clientHeightelement.scrollWidth/scrollHeightelement.getBoundingClientRect()navigator.language)navigator.onLine)navigator.getBattery())screen.orientation)'ontouchstart' in window)useEffect内で初期化した状態を初回レンダリングで使用useStateの初期値に関数を使い、その中でブラウザAPIを呼び出しuseMemo/useCallback内でのブラウザAPI使用typeof window !== 'undefined' での条件分岐後の出力process.env.NODE_ENV に基づく条件分岐(一部のケース)contentEditable要素の内容// ❌ 危険: 直接使用
const Component = () => {
return <div>{window.innerWidth}</div>
}
// ✅ 安全: useEffectで初期化
const Component = () => {
const [width, setWidth] = useState<number | null>(null)
useEffect(() => {
setWidth(window.innerWidth)
}, [])
return <div>{width ?? 'Loading...'}</div>
}
// ✅ 安全: dynamic import with ssr: false
const ClientOnlyComponent = dynamic(
() => import('./ClientComponent'),
{ ssr: false }
)
これらを意識することでHydration Errorを防ぐことができます。