EY-Office ブログ

Next.jsで不思議なエラーが発生、そうかSSRなのか!

先週のブログに書いたようなコードを仕事で書いていて、不思議なエラーに出会ってしまいました。

環境は以下のとおりです、

  • Next.js v14.1.0
  • Pages Routerモード

server side redering

出会ったエラー

以下のReactのプログラムはViteで使った環境では動作し、ブラウザー画面の幅が表示されます。

import { useMemo } from "react";

export default function Home() {
  const width = useMemo(() => {
    return  window.innerWidth;
  }, []);

  return (
    <>
      <p>Width: {width}</p>
    </>
  );
}

しかし、Next.jsで作った環境では以下のようなエラーが発生してしまいます。

windowオブジェクトはブラウザーが標準でもっていいるオブジェクトです。なぜそれが無いの?
コードを以下のように修正すると動作します。なぜ?

import { useState, useEffect } from "react";

export default function Home() {
  const [width, setWidth] = useState(0);

  useEffect(() => {
    setWidth(window.innerWidth);
  }, []);

  return (
    <>
      <p>Width: {width}</p>
    </>
  );
}

いろいろと調べて、やっと判りました。Next.jsはデフォルトで、Server Side Rendering(SSR)で動作しています。

  1. サーバー側でReactコードを実行し、HTMLに変換できる部分はサーバー側で作成
    • 開発モードではローカル開発サーバーで実行
  2. それをブラウザーにHTMLを送り表示
  3. その後、ReactコードをコンパイルしたJavaScriptをブラウザーに送る
  4. JavaScriptを実行し必要な部分のみを更新

という動作をしています。エラーになったコードではuseMemo()がサーバー側(開発サーバー)のNode.jsで実行するので、windowオブジェクトは無くエラーになったわけです。
useEffect()を使ったコードが正しく動くのは、useEffect()は画面表示後に実行されるのでブラウザー(ハイドレーション)での実行が保証されるわけです。

おまけ

次のコードをNext.jsで実行すると、

import { useMemo } from "react";

export default function Home() {
  const width = useMemo(() => {
    return  Math.random();
  }, []);

  return (
    <>
      <p>Width: {width}</p>
    </>
  );
}

サーバーで実行した時とブラウザーで実行した時で乱数の値が違うので、このような不思議なエラーになるのです。😅

SSRを止めるには

Next.jsのドキュメントにはWith no SSRという項目があり、SSRを実行しないようにも設定できます。

今回のコード等で試すには、共通ページpages/_app.tsxを以下のようにするとSSRが止まり、Vite等で作ったアプリと同じように動作します。

import type { AppProps } from "next/app";
import dynamic from "next/dynamic";
import React from "react";

const App = ({ Component, pageProps }: AppProps) => {
  return <Component {...pageProps} />;
};

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

まとめ

ReactオフィシャルドキュメントのReact プロジェクトを始めるではReactプロジェクト作成にはNext.js等のフレームワークを薦めていますが、今回のエラーのようにフレームワークの特性から起きるエラーに出会う可能性もあります。

モヤモヤ🤔

- about -

EY-Office代表取締役
・プログラマー
吉田裕美の
開発者向けブログ