Next.jsでwindow is not definedというエラーが発生する場合の対処方法

Next.jsでwindow is not definedというエラーが発生する場合の対処方法

Next.jsで「window is not defined」というエラーが発生するのは、通常、サーバーサイドレンダリング(SSR)を行っている際に、クライアントサイドにのみ存在するwindowオブジェクトにアクセスしようとした場合です。
windowオブジェクトはブラウザ環境でのみ使用可能で、サーバーサイドでは存在しないため、SSRのタイミングでエラーが発生します。
この問題を解決するためには、いくつかの対策方法があります。

1. クライアントサイドでのみコードを実行する

windowオブジェクトに依存するコードをクライアントサイドでのみ実行するように条件分岐を追加します。
Next.jsではtypeof window !== 'undefined'を使用して、windowが利用可能かどうかをチェックできます。

import { useEffect, useState } from 'react';

function MyComponent() {
  const [windowWidth, setWindowWidth] = useState(0);

  useEffect(() => {
    // クライアントサイドでのみ実行
    if (typeof window !== 'undefined') {
      setWindowWidth(window.innerWidth);
    }
  }, []);

  return <div>Window width: {windowWidth}</div>;
}

export default MyComponent;

2. ダイナミックインポートを使用する

Next.jsのdynamic関数を使用して、特定のコンポーネントをクライアントサイドでのみレンダリングするようにすることも可能です。
これにより、サーバーサイドレンダリングを回避できます。

import dynamic from 'next/dynamic';

const MyComponent = dynamic(() => import('./MyComponent'), {
  ssr: false, // サーバーサイドレンダリングを無効化
});

export default function Home() {
  return <MyComponent />;
}

3. useEffectを利用する

useEffectはクライアントサイドでのみ実行されるため、windowオブジェクトを扱う処理はこのフック内に記述することが推奨されます。
これにより、サーバーサイドレンダリング時にwindowオブジェクトにアクセスしようとしてエラーが発生するのを防ぐことができます。

import { useEffect } from 'react';

function MyComponent() {
  useEffect(() => {
    console.log(window.location.href); // クライアントサイドでのみ実行
  }, []);

  return <div>Check the console</div>;
}

export default MyComponent;

4. カスタムフックを使用する

クライアントサイド専用の処理を管理するためにカスタムフックを作成することもできます。
これにより、コードの再利用性が向上し、クリーンな構造を保てます。

import { useEffect, useState } from 'react';

function useWindowWidth() {
  const [windowWidth, setWindowWidth] = useState(0);

  useEffect(() => {
    if (typeof window !== 'undefined') {
      const handleResize = () => setWindowWidth(window.innerWidth);
      window.addEventListener('resize', handleResize);
      handleResize(); // 初回実行

      return () => window.removeEventListener('resize', handleResize);
    }
  }, []);

  return windowWidth;
}

function MyComponent() {
  const width = useWindowWidth();

  return <div>Window width: {width}</div>;
}

export default MyComponent;

5. サーバーサイドレンダリングを明示的に無効化する

コンポーネントやページ全体でサーバーサイドレンダリングを無効にすることも一つの方法です。
これには、Next.jsの設定や、getStaticPropsやgetServerSidePropsを使わない構成にするなどの対策があります。

import dynamic from 'next/dynamic';

const NoSSRComponent = dynamic(() => import('../components/NoSSRComponent'), {
  ssr: false,
});

export default function Home() {
  return <NoSSRComponent />;
}

まとめ

Next.jsで「window is not defined」というエラーを避けるには、windowオブジェクトへのアクセスがクライアントサイドでのみ行われるようにすることが重要です。
上記の方法を使用して、windowに依存するコードを適切に管理することで、サーバーサイドレンダリングにおける問題を解決できます。