【入門編】 React Strict Modeにおける二重実行 – React実践ガイド

こんにちは!Reactの学習、楽しく進められていますか?
画面がスイスイ動くのは楽しいけれど、新しい概念や「おや?」と思う挙動に出会うと、ふと手が止まってしまいますよね。

特に、Reactを学び始めて多くの人が「あれっ!?」とパニックになりがちで、かつ現場のプロもめちゃくちゃ大切にしているテーマがあります。それが、「開発環境(Strict Mode)で、`useEffect`がなぜか2回実行されてしまう現象」です。

コンポーネントを読み込んだだけで、コンソールにログが2回ポツポツと表示されるのを見ると、「私のコード、何か変なバグを埋め込んでしまったのでは…!?」と冷や汗が出ますよね。

でも、どうか安心してください。あなたのコードは間違っていません。それはReactからの「優しさ」であり、未来のバグを防ぐための重要なサインなんです。今日は、身近な例えを交えながら、この「2回実行の秘密」と「クリーンアップ関数」という心強い味方について、ゆっくり紐解いていきましょう!

—

1. なぜ? Strict Modeでの「2回実行」の正体

まずは、なぜこんなことが起きるのか、その理由からお話ししますね。

Reactには、Strict Mode(厳格モード)という、開発中だけにこっそり作動する「お節介なチェック機能」があります。これは、あなたのコードの健康診断をしてくれる専属トレーナーのような存在です。

このトレーナーは、開発環境である実験を行う習性があります。それは、「コンポーネントを画面に出したり(マウント)、一瞬で引っ込めたり(アンマウント)、もう一回出したり(再マウント)」というリハーサルを、ページを開いた瞬間に猛スピードで行うのです。

身近な例えで考えてみましょう:自動ドアのセンサー

想像してみてください。あなたは今、新しいお店の「自動ドアのセンサー」を作っています。
お店の入り口に人が来たら(コンポーネントが表示されたら)、ピッと音が鳴るプログラムを `useEffect` で書きました。

普通のモードだと、お客さんが1人来たら「ピッ」と1回鳴って終わりです。
しかし、Strict Modeという厳しいチェック官が来ると、こう言います。

> 「ちょっと待って! お客さんが入ってきた直後に、一瞬だけ外に出て、もう一回入り直したときの動作テストもしておこう!」

つまり、
1. お店に入る(1回目の実行)
2. 一瞬外に出る(クリーンアップの実行)
3. もう一度お店に入る(2回目の実行)

というリハーサルを、私たちの知らないところで一瞬のうちにやってのけるのです。これが、開発環境で `useEffect` が2回動く仕組みです。本番環境(ユーザーが実際に使う公開後)では、このリハーサルは行われず、通常通り1回しか実行されないので安心してくださいね。

—

2. なぜこんなテストをするの?(Reactの深い愛)

「わざわざ2回も動かして、混乱させないでよ!」って思いますよね。でも、これにはちゃんとした深い理由があるんです。

Webアプリを作っていると、こんな問題がよく起きます。

  • ページから別のページに移動したのに、裏でずっとタイマーが動き続けてメモリを食いつぶしている。
  • サーバーとの通信が中途半端に残っていて、エラーが起きる。

これらはすべて、「画面から消えたあとの後片付け(お掃除)」を忘れていることが原因です。

Strict Modeは、「ほら、画面から一瞬引っ込んだときに、ちゃんとお部屋を片付け(クリーンアップ)できてますか? 片付けを忘れていると、本番環境でメモリ漏れ(メモリリーク)という大変なバグになりますよ!」ということを、事前に教えてくれているんです。

つまり、2回実行されるのは、「あなたのコードが、お片付け上手かどうかを試されているテスト」なんだと思ってあげてください。

—

3. 「お片付け」の主役:クリーンアップ関数とは?

ここで登場するのが、`useEffect` の中でひっそりと返される関数、クリーンアップ関数です。

難しく考える必要はありません。これは、「この部屋を出るときに、電気を消して、鍵を閉めてね」というお掃除の予約です。

言葉だけだとイメージしにくいと思うので、具体的なコードを見てみましょう。ここでは、毎秒カウントが増える「タイマー」を例にします。

実用的なサンプルコード

import React, { useState, useEffect } from ‘react’;

function TimerComponent() {
const [count, setCount] = useState(0);

useEffect(() => {
// — 【セットアップ】コンポーネントが表示された時に動く処理 —
console.log(‘【セットアップ】タイマーをスタートします!’);

// 1秒ごとにカウントを1ずつ増やすタイマーをセット
const timerId = setInterval(() => {
setCount((prevCount) => prevCount + 1);
}, 1000);

// — 【クリーンアップ関数】コンポーネントが消える時(お片付け)に動く処理 —
return () => {
console.log(‘【クリーンアップ】タイマーを止めます(お片付け)!’);

// 動きっぱなしを防ぐために、セットしたタイマーをしっかりクリアする
clearInterval(timerId);
};
}, []); // 依存配列が空なので、最初のマウント時に実行される

return (

);
}

export default TimerComponent;

このコードをStrict Modeが有効な環境で動かすと、コンソールには次のような順番でログが表示されます。

1. `【セットアップ】タイマーをスタートします!` (1回目)
2. `【クリーンアップ】タイマーを止めます(お片付け)!` (Strict Modeによる一瞬のお片付け)
3. `【セットアップ】タイマーをスタートします!` (本番用の2回目・再スタート)

もし、ここに「クリーンアップ関数(お片付けの仕組み)」書き忘れていると、タイマーが止まらないまま2つ目が重なって動き出してしまい、時間の進み方が倍速になったり、予期せぬバグを引き起こしたりします。
Strict Modeはこのミスを未然に防いでくれる、最高に頼れる相棒なのです。

—

4. 初学者のあなたが今日から意識すべきポイント

「ふう、なんだか仕組みはわかったけれど、開発中にコンソールが2回ログを出すのがやっぱりちょっと気になる……」という方へ。

実務や学習において、以下の心構えを持っておくと心がとても軽くなりますよ。

1. 「開発中の2回実行は仕様だ」と割り切る
コンソールにログが2回出るのは、Reactが「ちゃんと動いてるよー、お片付けもできるかなー?」とチェックしている証拠です。エラーでアプリが壊れているわけではないので、まずは深呼吸しましょう。

2. 「外の世界」と繋がるときは、必ずクリーンアップを書く癖をつける

  • `setInterval` や `setTimeout` などのタイマーを使うとき
  • `window.addEventListener` などのイベントリスナーを登録するとき
  • 外部のサーバーとリアルタイム通信(WebSocketなど)をつなぐとき

これらはすべて「自分のお部屋の外」とやり取りする仕組みです。お部屋を出るときは、「つないだコードを元に戻す(片付ける)」処理を `return` の中に必ず書く、とセットで覚えておいてください。

3. どうしても気になる場合の裏技(※最終手段)
どうしてもStrict Modeの挙動に精神が削られる場合は、プロジェクトの根幹にある `index.js` (または `main.js` / `App.js`)の `` タグを一時的に外すという選択肢もあります。
ただ、これはあくまで「一時しのぎ」です。アプリが大きくなったときにバグを見つけにくくなるため、基本的にはStrict Modeの環境に慣れていくのが、将来のあなたを助ける一番の近道ですよ。

—

まとめ:Reactからのメッセージを受け取ろう

いかがでしたでしょうか?
「Strict Modeでの二重実行」は、最初に出会うとちょっとビビってしまうReactの仕様の一つです。

でも、その裏側には「本番環境でユーザーが使うときに、絶対にメモリリークやバグを起こさせない!」というReactチームの強いこだわりと優しさが隠されています。

コンソールが2回動いているのを見かけたら、

  • 「おっ、Reactクンがちゃんとお片付けのテストをしてくれてるな」
  • 「よし、このエフェクトには綺麗なお片付け(クリーンアップ関数)を用意しておこう!」

そう心の中で微笑みながら、コードを書いてみてくださいね。
あなたのReact学習の旅が、少しでも楽しく、心温まるものになりますように。応援しています!

コメント

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