React Strict Mode:ただの「お節介な警告」と片付ける前に知っておくべき、開発の生命線
現場でコードを書いていて、`useEffect` の中身がコンソールで2回動いて「なんだこれ、バグか?」と焦ったことはないだろうか。もし君がそう思ったのなら、それはReactからの重要なメッセージだ。
多くの開発者が開発環境で `React.StrictMode` を外し、「これでログが綺麗になった!」と安心する。だが、それは飛行機の警告灯をガムテープで塞ぐようなものだ。今回は、なぜStrict Modeがわざわざ「二重実行」なんていう奇妙な挙動をするのか、そしてそれがどう我々のアプリケーションを「未来のバグ」から守っているのかを紐解いていこう。
—
なぜReactはわざと「二重実行」するのか?
結論から言えば、「副作用を純粋に保て」というReactからの強制的なメッセージだ。
React 18以降のStrict Modeでは、開発環境において「マウント → アンマウント → 再マウント」というプロセスを強制的に実行する。これは、君の書いたコンポーネントが「何度再実行されても同じ結果を返すか(冪等性)」をテストしているんだ。
もし君の `useEffect` が、外部のグローバル変数に依存していたり、クリーンアップ関数(`return () => { … }`)を書き忘れていたりすると、この二重実行によってメモリリークや意図しないAPIリクエストの重複が露見する。つまり、本番環境でユーザーを悩ませる前に、開発段階で「副作用の設計ミス」を炙り出しているというわけだ。
—
実践:Strict Modeと仲良くする「副作用」の書き方
現場でよくあるミスは、クリーンアップ関数を軽視することだ。以下のコードは、Strict Mode下で二重実行されても安全に動く「正解」に近いパターンの例だ。
import { useState, useEffect } from ‘react’;
const DataFetcher = ({ userId }) => {
const [data, setData] = useState(null);
useEffect(() => {
// 開発環境のStrict Modeでは、この処理が2回走る可能性がある
let isActive = true;
const fetchData = async () => {
try {
const response = await fetch(`/api/users/${userId}`);
const result = await response.json();
// コンポーネントがアンマウントされた後に結果をセットしないようにする
if (isActive) {
setData(result);
}
} catch (e) {
console.error(“fetch failed”, e);
}
};
fetchData();
// これが「クリーンアップ関数」。
// Strict Modeの二重実行時、1回目のマウント直後にこれが呼ばれる。
// APIリクエストの競合を防ぐための重要な保険だ。
return () => {
isActive = false;
console.log(“クリーンアップ:副作用を破棄しました”);
};
}, [userId]); // 依存配列の管理も忘れずに
return
;
};
ここがポイント:
1. `isActive` フラグの活用: 非同期処理の結果を、コンポーネントが生きている時だけ適用する。
2. クリーンアップ関数の徹底: 外部との接続(WebSocketやイベントリスナーの購読)は必ずここで解除する。これを書かないと、Strict Modeは「君のコードはメモリを垂れ流す可能性があるぞ」と教えてくれているようなものだ。
—
非推奨APIの警告:未来の負債を今すぐ返済する
Strict Modeのもう一つの役割は、`findDOMNode` や `componentWillMount` といった、Reactチームが「もう使うな」と言っているレガシーAPIを使用している場合に警告を出してくれることだ。
これらは単なる嫌がらせではなく、Reactの「Concurrent Features(同時実行機能)」をフル活用するために排除しなければならない過去の遺物だ。React 19へのアップグレードや、将来のマイナーアップデートで突然アプリが動かなくなるという地獄を見ないためにも、この警告を無視してはいけない。
—
最後に:シニアエンジニアからの助言
Strict Modeは「開発者の体験を少しだけ不快にさせる」ことで、「コードの品質を強制的に引き上げる」というトレードオフを選択している。
もし君のチームで「Strict Modeが邪魔だから外そう」という意見が出たら、それは「テストを書くのが面倒だから仕様書を消そう」と言っているのと同義だ。もしどうしても二重実行が業務上許容できない副作用(例:外部SDKの初期化など)を伴う場合は、`useRef` を使って実行済みフラグを立てる等の「実務的な回避策」を講じるのがプロの流儀だ。
Reactの仕様は、ただのルールじゃない。それは何万人ものエンジニアが踏んできた「地雷」を避けるための地図なんだ。ぜひ、その地図を無視せず、使いこなしてほしい。
何かあれば、またいつでも聞きに来てくれ。共に泥臭く、最高のアウトプットを目指そうぜ。

コメント