こんにちは。フロントエンドの現場で日々コードと格闘しているチーフアーキテクトです。
Reactを学び始めたばかりの皆さん、まずはここまで辿り着いた自分を褒めてあげてください。Reactは奥が深く、時に「え、どうしてそんな動きをするの?」と首を傾げたくなる挙動にぶつかることもありますよね。
その代表格が、「開発中に`useEffect`がなぜか2回動いてしまう!」という現象です。コンソールにログを出したら、なぜか同じものが2つ並んでいる……。「僕のコード、何か壊しちゃったかな?」と不安になる必要はありません。実はそれ、Reactがあなたのコードを「守るために」行っている愛ある仕打ちなんです。
今日はその謎を、一緒に紐解いていきましょう。
—
なぜReactは「二度手間」をかけるのか?
まずイメージしてみてください。あなたは新しいお店を開く準備をしています。オープン初日、お客さんが来ても慌てないように、店長であるあなたは「リハーサル」を入念に行いますよね。
Reactの「Strict Mode(厳格モード)」は、まさにこの「リハーサル」なんです。開発環境において、Reactはわざと`useEffect`を2回実行することで、あなたの作ったシステムが「何度やり直しても同じ結果になるか?」をチェックしています。
もし1回目と2回目で結果が違ってしまったら、それは「予期せぬトラブルが起きる可能性があるよ」というサイン。Reactは、本番環境でユーザーが困らないように、開発中に厳しくチェックしてくれているんです。
—
副作用の「冪等性(べきとうせい)」って何だ?
少し難しい言葉が出ましたが、現場で大事なのは「冪等性(べきとうせい)」という考え方です。
これは「何度やっても結果が同じになる」こと。例えば、自動販売機のボタンを押す動作を考えてみてください。
- ボタンを押してコーラが出る(成功)
- もう一度押して、またコーラが出る(成功)
もし2回押した時に「コーラが2本出てきて、さらに機械が故障した」としたら、それは問題ですよね。副作用もこれと同じで、「何度実行されても、アプリの状態が正しく保たれているか」が重要なんです。
—
実際にコードで見てみよう
例えば、画面が表示された時にデータを読み込む処理を書いてみたとします。
import { useEffect } from ‘react’;
function MyComponent() {
useEffect(() => {
// 画面が表示された時に動く処理
console.log(“データの読み込みを開始しました!”);
// ここに「お片付け」処理を書くのが重要!
return () => {
console.log(“お片付け:次の読み込みのために一旦リセットします”);
};
}, []); // 空の配列は「最初の一回だけ」という意味
return
;
}
このコードをStrict Modeで動かすと、コンソールにはこう出ます。
1. `データの読み込みを開始しました!`
2. `お片付け:次の読み込みのために一旦リセットします`
3. `データの読み込みを開始しました!`
「お片付け」の関数(クリーンアップ関数と言います)がちゃんと動いていることが分かりますね。これが「何度やり直しても、最後は綺麗な状態でスタートできる」という安心感を生むんです。
—
「お片付け」を忘れないためのコツ
`useEffect`を使うときは、常に「この処理をやり直すことになったら、何を残すとまずいかな?」と考える癖をつけてください。
- タイマーをセットしたら: `clearInterval` で止める。
- 通信を開始したら: キャンセル処理を入れる。
- イベントリスナーを登録したら: `removeEventListener` で削除する。
「お片付け」をしっかり書いておけば、Reactが2回実行しようが100回実行しようが、アプリは一切動じません。これが、実務でバグに強いコードを書くためのプロの作法です。
—
最後に:つまずくのは成長の証です
Reactが「二度実行」という少し意地悪なテストをしてくるのは、あなたが書いたコードを、世界中のユーザーが安心して使える「堅牢なもの」にしたいからです。
もしコンソールにログが2つ並んでいても、「よし、Reactがリハーサルしてくれているな」と心の中で微笑んであげてください。そして、「お片付け(クリーンアップ関数)」をしっかり書き込む。これだけで、あなたの書くコードは一段階、いや二段階上のレベルに到達します。
最初は難しく感じるかもしれませんが、大丈夫。一つひとつ、道具の使い方に慣れていきましょう。困ったときはいつでもここに戻ってきてくださいね。応援しています!

コメント