フロントエンド開発の先端を突っ走るNext.js
next.js アプリの初期化( npx create-next-app@latest <アプリ名> ) または pnpm create next-app@latest <アプリ名> または bun create next-app <アプリ名> )

next.js で hydration error が起きる可能性があるものを調べる。

Next.jsのHydration Errorが起きる可能性があるものを包括的にリストアップします。

1. ブラウザAPI関連

Window/Document オブジェクト

  • window.innerWidth / window.innerHeight
  • window.outerWidth / window.outerHeight
  • window.scrollX / window.scrollY
  • window.pageXOffset / window.pageYOffset
  • window.screen.width / window.screen.height
  • window.screen.availWidth / window.screen.availHeight
  • window.devicePixelRatio
  • window.location.* (href, pathname, search, hash等)
  • window.history.*
  • window.navigator.* (userAgent, language, onLine等)
  • document.documentElement.clientWidth/clientHeight
  • document.body.*
  • document.cookie
  • document.referrer
  • document.getElementById() などのDOM参照

ストレージAPI

  • localStorage.getItem()
  • sessionStorage.getItem()
  • indexedDB

メディアクエリ

  • window.matchMedia('(prefers-color-scheme: dark)')
  • window.matchMedia('(min-width: 768px)')
  • その他全てのメディアクエリ

その他のブラウザAPI

  • navigator.geolocation
  • navigator.mediaDevices
  • navigator.bluetooth
  • navigator.clipboard
  • navigator.credentials
  • Notification API
  • IntersectionObserver
  • ResizeObserver
  • MutationObserver
  • PerformanceObserver
  • requestAnimationFrame
  • requestIdleCallback

2. 日付・時刻関連

  • new Date() (現在時刻)
  • Date.now()
  • performance.now()
  • タイムゾーン依存の処理 (Intl.DateTimeFormatの結果)
  • new Date().getTimezoneOffset()
  • サーバーとクライアントで時刻がズレている場合の全ての日時表示

3. ランダム値・一意な値

  • Math.random()
  • crypto.randomUUID()
  • crypto.getRandomValues()
  • ランダムに生成されるID
  • タイムスタンプベースの一意なID (サーバーとクライアントで異なる時刻)

4. ユーザー固有の情報

  • ログイン状態 (クライアントで判定する場合)
  • ユーザー設定 (localStorageから取得)
  • Cookie情報 (document.cookieで取得)
  • セッション情報
  • 認証トークン

5. CSS/スタイル関連

  • getComputedStyle()
  • element.offsetWidth/offsetHeight
  • element.clientWidth/clientHeight
  • element.scrollWidth/scrollHeight
  • element.getBoundingClientRect()
  • CSS-in-JSでのクライアント依存の値

6. 環境・設定関連

  • ダークモード/ライトモードの検出
  • システムの言語設定
  • システムのタイムゾーン
  • ブラウザの言語設定 (navigator.language)
  • オンライン/オフライン状態 (navigator.onLine)
  • バッテリー情報 (navigator.getBattery())
  • デバイスの向き (screen.orientation)
  • タッチデバイス判定 ('ontouchstart' in window)

7. サードパーティライブラリ

  • クライアントサイドのみで動作するライブラリ
  • ブラウザAPIに依存するライブラリ
  • 動的インポートのタイミング

8. コンポーネントライフサイクル

  • useEffect内で初期化した状態を初回レンダリングで使用
  • useStateの初期値に関数を使い、その中でブラウザAPIを呼び出し
  • useMemo/useCallback内でのブラウザAPI使用

9. 条件分岐

  • typeof window !== 'undefined' での条件分岐後の出力
  • process.env.NODE_ENV に基づく条件分岐(一部のケース)
  • ユーザーエージェントによる条件分岐

10. その他

  • Web Workers
  • Service Workers
  • WebSocket接続状態
  • WebRTC
  • Canvas/WebGL (動的生成される内容)
  • contentEditable要素の内容
  • フォーム要素の値(制御されていない場合)
  • サーバーとクライアントでのReactバージョンの違い
  • 外部スクリプトによるDOM操作
  • ブラウザ拡張機能によるDOM変更

安全な対処パターン

// ❌ 危険: 直接使用
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を防ぐことができます。

No.2715
02/03 14:20

edit