React初心者がハマりがちな「useEffectの無限ループ」──原因と実例をまとめて解説

React を使い始めると、誰もが一度は遭遇する「useEffect の無限ループ」。私自身も依存配列の指定を忘れたり、意図せず state を更新してしまったりして、画面が固まる経験を何度もしました。

なぜ useEffect は無限ループしてしまうのか?どう書けば防げるのか?

この記事では、初心者でも理解しやすいように、React の内部動作とともに原因と対策を整理して解説します。

React を触り始めると、多くの人が一度は遭遇するのが useEffect の無限ループ です。

私自身も開発中に、

  • useEffect(() => {}) と依存配列を書き忘れて無限ループ
  • useEffect(() => {}, [var]) の依存がズレて無限ループ

といった初歩的なミスに何度かハマってきました。

この記事では、実際に起こりやすいパターンと、なぜそうなるのかをシンプルにまとめます。


■ 1. 依存配列を書き忘れると無限ループになる

もっとも多いミスがこれです。


useEffect(() => {
  setCount(count + 1); // ← state 更新
});

依存配列 [] がないと、useEffect は 毎回のレンダー後に必ず実行されます
その中で state を更新すると、再レンダーが起き、また useEffect が走り…
永久ループが完成します。

✔ 正しい書き方(初回だけ動かす)


useEffect(() => {
  setCount(count + 1);
}, []);

■ 2. 依存配列に“更新している値”を入れるとループが発生する

たとえば次の例。


useEffect(() => {
  setData([...data, "new"]);
}, [data]);

data を更新すると → data が変わる → useEffect が再実行 → また更新…
というループが起きてしまいます。

✔ 対策:関数型アップデートを使う


useEffect(() => {
  setData(prev => [...prev, "new"]);
}, []);

prev が常に最新値なので、data を依存に入れる必要がなくなります。


■ 3. 関数が原因で無限ループするパターン

関数は毎レンダーで新しく生成されるため、依存が変わってしまいます。


const update = () => {
  setValue(value + 1);
};

useEffect(() => {
  update();
}, [update]); // update が毎回変わるので無限ループ

✔ 対策:useCallback で固定する


const update = useCallback(() => {
  setValue(v => v + 1);
}, []);

useEffect(() => {
  update();
}, [update]);

【Tips】なぜ依存配列を書かないと無限ループするの?

仕組みを一度理解しておくと、一気にミスが減ります。

① useEffect はデフォルトで“毎レンダー後に実行される”

依存配列([])がない場合、React はこう解釈します。

「条件がないなら、毎回実行するしかない」


② useEffect 内で state を更新すると、必ず再レンダーが起きる


useEffect(() => {
  setCount(count + 1);
});

これを行うと、

  1. レンダー
  2. effect 実行
  3. state 更新
  4. 再レンダー
  5. effect 実行(以下ループ)

という構造が自動的に成立します。


③ 依存配列は“いつ effect を実行するか”を React に伝えるためのもの

  • [] → 初回だけ
  • [count] → count が変わった時だけ

「何も指定しない」という状態が、一番危険なのです。


1行まとめ

依存配列を書かない =「毎回実行して」と命令している。
その中で state を更新すれば、再レンダー → effect → 再レンダーの無限ループが成立する。


■ 4. 無限ループを防ぐためのチェックリスト

  • 依存配列の書き忘れはない?
  • useEffect 内で更新している値を依存に入れていない?
  • 関数を依存にするなら useCallback で固定してる?
  • React が変化を追跡できる値だけ依存にしている?
  • 初回のみ実行したいなら [] でOK?

■ まとめ

useEffect の無限ループは

  • 依存配列の設定ミス
  • 更新対象と依存対象が一致してしまっている
  • 関数が毎レンダーで再生成されている

この3つがほぼすべてです。

依存配列には 必要最小限だけ記述する
そして prev を使った関数型アップデートを活用することで、
ほとんどの無限ループは防げます。

コメント

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