React18(含Next.js)の開発環境でuseEffectが2回実行されてしまう場合の対処法

自分が開発しているプロジェクトで、React17.0.2でNext.jsを使用していたのですが、React18の正式リリースから2ヶ月、そろそろ頃合いかと思いReactを18.1.0にアップグレードしてみました。(併せてNext.jsも最新バージョンにアップグレード)

が、それからというもの、ローカルで開発環境を立ち上げているときだけ、何故かuseEffectが2回実行されるようになってしまいました。

import type { NextPage } from "next"
import { useEffect } from "react"

const Index: NextPage = () => {
  useEffect(() => {
    console.log("componentDidMount")
    
    return () => console.log("componentWillUnmount")
  }, [])

  return null
}

export default Index

こんなソースを書いてみました。普通なら、componentDidMountと1回出力されるだけです。

(゜д゜)

ソースとにらめっこしても何もおかしな所はない、だけど何故かアンマウントを挟んで2回実行される。

不可解な現象に唸っていたところ、その理由と対処法が分かりましたので書いていきます。

StrictMode

結論から言うと、React18の新機能である「StrictMode」というのが原因です。直訳すると「厳密モード」ですかね。

現在、StrictMode は以下のことに役立ちます。
・安全でないライフサイクルの特定
・レガシーな文字列 ref API の使用に対する警告
・非推奨な findDOMNode の使用に対する警告
・意図しない副作用の検出
・レガシーなコンテクスト API の検出
・state の再利用性を保証する

https://ja.reactjs.org/docs/strict-mode.html

という風に、ありがたい恩恵を授かれるそうです。しかし…

今回実際の自分のケースでは、useEffectの中にSocket.IOのイベントハンドラーを記述していたのですが、このStrictModeの仕様が仇となり、イベントハンドラーが2つ待ち受けてる状態になってしまい、処理が二重に行われるといったことがありました。

※StrictModeについて、詳しくはこのページが非常にわかりやすいです。

ReactでStrictModeを無効化させる

無効化はとても簡単です。

プロジェクトルートにあるindex.jsを開き、renderメソッドの中にあるReact.StrictModeタグを消します。

// 略
root.render(
  <React.StrictMode> // ←消す
    <App />
  </React.StrictMode> // ←消す
);
// 略

Next.jsでStrictModeを無効化させる

こちらも簡単で、プロジェクトのルートディレクトリーにあるnext.config.jsを開き、

/** @type {import('next').NextConfig} */
const nextConfig = {
  reactStrictMode: false, // <= trueからfalseに!!
}

module.exports = nextConfig

3行目のreactStrictModeプロパティーをtrueからfalseにします。

編集できたら開発環境のサーバーを再起動します。

これで無事、開発環境においても意図した挙動をするようになりました👍

コメント

タイトルとURLをコピーしました