自分が開発しているプロジェクトで、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 は以下のことに役立ちます。
https://ja.reactjs.org/docs/strict-mode.html
・安全でないライフサイクルの特定
・レガシーな文字列 ref API の使用に対する警告
・非推奨な findDOMNode の使用に対する警告
・意図しない副作用の検出
・レガシーなコンテクスト API の検出
・state の再利用性を保証する
という風に、ありがたい恩恵を授かれるそうです。しかし…
今回実際の自分のケースでは、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
にします。
編集できたら開発環境のサーバーを再起動します。
これで無事、開発環境においても意図した挙動をするようになりました👍
コメント