useEffectが無限ループになる

依存配列の設定ミスによる再実行の連鎖を防ぐ


❓ よくある現象

  • ページが読み込まれた瞬間、useEffectが無限に呼ばれ続ける
  • ブラウザが重くなる、APIが何度も呼び出される
  • 開発ツールで「更新のたびに再レンダリング」が確認できる

🚨 典型的なミスの例

❌ NGコード:状態を更新しているのに依存配列に含めていない

const [count, setCount] = useState(0)

useEffect(() => {
  setCount(count + 1)  // ← これが state を更新 → 再レンダリング → 再実行 の無限ループに
}, [])

✅ 対策:

  • 状態を更新する場合は、依存関係が変化しないような記述を避ける
  • または setStateuseEffect 外で使う

💥 よくある原因まとめと対処

原因 説明 対策
依存配列が空なのに setState() を使っている 初回に実行 → 更新 → 再実行 の連鎖 setStateuseEffect 外で使う
依存配列に毎回新しく生成されるオブジェクトを入れている オブジェクトや関数の参照が毎回変わる useMemouseCallback でメモ化する
依存配列の記述漏れ・不要な依存の追加 実際に変化しない値でも再実行のトリガーになっている 依存配列を必要最小限にする(ESLintの警告も参考に)

✅ 正しい例

const [data, setData] = useState([])

useEffect(() => {
  fetch('/api/items')
    .then((res) => res.json())
    .then((json) => setData(json))
}, [])  // 初回だけ実行される

⚙️ オブジェクトや関数を依存に入れるとき

❌ NG例

const filters = { category: 'all' }

useEffect(() => {
  fetchItems(filters)
}, [filters])  // filtersは毎回新しいオブジェクトになるので再実行される

✅ 修正:useMemoでメモ化

const filters = useMemo(() => ({ category: 'all' }), [])

useEffect(() => {
  fetchItems(filters)
}, [filters])

✅ まとめ:無限ループ対策ポイント

チェック項目 実施すること
useEffect内で状態を更新しているか? その状態が再実行の原因になっていないか
依存配列に毎回変わる値(関数・オブジェクト)を入れてないか useMemo / useCallback を使う
依存配列が適切か? ESLint(exhaustive-deps)の指摘を確認する

🔗 参考

コメントを残す 0

Your email address will not be published. Required fields are marked *