はじめに
React18 でレンダリングする際の挙動が予想と違く混乱したので記事にまとめたいと思います。
Version
$ node -v
v16.15.1
"react": "18.2.0"
React18 の挙動
useEffect(() => {
console.log('mount')
return () => {
console.log('unmount')
}
}, [])
まずこちらの挙動は初回レンダリング時にどうなるでしょうか?ちなみにuseEffectは戻り値を設定すると、クリーンアップ関数としてDOMが破棄された際に中の処理が実行されます。
mount
今まで普通にReactを使っていた方々であれば、このようになると思うはずです。なぜならDOMは破棄していないのでクリーンアップ関数は実行されないからです。ですが実はReact18から以下の様になります。
mount
unmount
mount
一度レンダリングを二回行なっているのですね。一般的な使い方をしているのであれば影響はないはずですがuseEffectの中で冪等ではない処理をもし行なっていた場合二回呼ばれてしまうので意図せぬ挙動をおこなってしまうかもしれないので注意ですね。
補足
補足するとこの挙動はReact18の中でもstrictモードかつ開発者モードの際に発生します。そのためつまり将来的なReactの設計としてレンダリングが複数行われたとしても挙動に問題ない様な構造にすることが求められていることがわかります。
対処法としてクリーンアップ時に処理を行わせるか以下の記事ではrefを使う方法を提案しています。
最終手段
どうしても今すぐこの挙動を外したい場合はstrictモードを解除しましょう。あくまで最終手段ですが。
<React.StrictMode> // この囲っているタグを消す
</React.StrictMode>
nextjsを使っているならこのように変更します。
const nextConfig = {
reactStrictMode: false,
}
まとめ
なぜこのような挙動を起こす様にしたのかは先程あげたこちらの記事にわかりやすく記載されているのでより詳しく知りたい方はこちらを読むと良いかもしれません。
また、Reactのレンダリングについては以前僕が記事にしているのでよろしければご覧ください。
参考文献