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

Next.js での SSR回避方法3選 ( hydration error , document error 回避)

SSRで hydration error , document error が起きる原因

Next.jsはサーバーコンポーネントとクライアントコンポーネントの両方をサポートしています。

  1. サーバーサイドレンダリング: コンポーネントがサーバー上でレンダリングされる際、documentwindow などのブラウザ専用オブジェクトは存在しません

  2. ハイドレーション: サーバーでレンダリングされたHTMLがクライアントに送られた後、Reactがブラウザ上でコードを「ハイドレート」(活性化)する過程で、このエラーが発生しています

解決方法

  1. useEffect を使用する:
import { useEffect, useState } from 'react';

function MyComponent() {
  const [mounted, setMounted] = useState(false);
  
  useEffect(() => {
    setMounted(true);
    // ここで安全に document にアクセスできる
  }, []);
  
  if (!mounted) {
    return null; // または初期表示用の代替表示
  }
  
  // document を使用するコード
  return <div>...</div>;
}
  1. next/dynamic を使用したコンポーネントの動的インポート:
import dynamic from 'next/dynamic';

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

function Page() {
  return <ClientSideComponent />;
}
  1. typeof window !== 'undefined' チェック:
function MyComponent() {
  const isBrowser = typeof window !== 'undefined';
  
  // document を使用するコードを条件付きで実行
  return (
    <div>
      {isBrowser && /* document を使用するコード */}
    </div>
  );
}
  1. 'use client' ディレクティブを使用: ファイルの先頭に 'use client' を追加すると、そのコンポーネントとその子コンポーネントはクライアントサイドでのみ実行されます。
'use client'

import { useEffect } from 'react';

export default function ClientComponent() {
  useEffect(() => {
    // ここで安全に document にアクセスできる
    const element = document.getElementById('some-id');
    // ...
  }, []);
  
  return <div>...</div>;
}

Next.jsではクライアントサイドの処理とサーバーサイドの処理を適切に分けることが重要です。document オブジェクトを使用する必要がある場合は、上記のいずれかの方法を使用して、そのコードがクライアントサイドでのみ実行されるようにしましょう。

● Next.js で dynamic import ( ssr: false ) による SSR回避(その1)

https://nextjs.org/docs/app/building-your-application/optimizing/lazy-loading

・export default の場合

import { MyComp } from "../components/MyComp";

  ↓

import dynamic from "next/dynamic";

const MyCompNoSSR = dynamic(() => import("./MyComp"), { ssr: false });

以上で、SSRが回避されます。

・named export の場合

import MyComp from "../components/MyComp";

  ↓

import dynamic from "next/dynamic";

const MyCompNoSSR = dynamic(
  () => import("./MyComp").then((modules) => modules.MyComp),
  { ssr: false },
);

以上です。

● Next.js で dynamic import ( ssr: false ) による SSR回避(その2)

このように 呼び出されるコンポーネント側に記述することもできます

import App from '../components/App'

export default function About() {
  return (
    <App>
      <p>About Page</p>
    </App>
  )
}

  ↓

import dynamic from 'next/dynamic'
import App from '../components/App'

const About = ()=> {
  return (
    <App>
      <p>About Page</p>
    </App>
  )
}

export default dynamic(() => Promise.resolve(About), {
  ssr: false
})

以上で、SSRが回避されます。

● SSR回避の確認方法

ページをリロードしてhtmlソースを見てみます。

<p>About Page</p>

がなければ、SSRされていません。

オプション With suspense

React18以上が必要です。必ずバージョンを確認しましょう

const DynamicLazyComponent = dynamic(() => import('../components/hello4'), {
  suspense: true,
})

https://nextjs.org/docs/advanced-features/dynamic-import

npm run dev の時だけ htmlソースを表示した時にエラーが出ることがあるようです

https://tinyurl.com/29s6yym5

No.2158
02/27 18:56

edit