React で「Too many re-renders」エラーが出るときの典型パターンまとめ

React を使っていると、
「Too many re-renders. React limits the number of renders to prevent an infinite loop.」
というエラーに遭遇することがあります。

これは 無限再レンダー(infinite re-render loop) が発生したときに表示されるもので、React 開発では非常に一般的なトラブルです。

この記事では、現場で特によく発生する「典型パターン」と「正しい対処法」をわかりやすく整理します。

パターン1:レンダー中に setState を呼んでしまう

最も多いパターンです。

❌ NG パターン

const MyComponent = () => {
  const [count, setCount] = useState(0);

  if (count === 0) {
    setCount(1); // ← レンダー中に state 更新 → 無限ループ
  }

  return <div>{count}</div>;
};

レンダー中に setState が呼ばれると、更新 → レンダー → 更新…となり、無限ループが発生します。

✅ OK パターン(useEffect を使う)

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

パターン2:useEffect の依存配列ミス

依存配列に 状態を毎回更新してしまう値 を入れていると無限ループになります。

❌ NG

useEffect(() => {
  setUser({ name: 'Alice' }); // 毎回新しいオブジェクト → 無限ループ
}, [user]);

user が毎回新しいオブジェクトになるため、依存が変わり続けてループします。

✅ OK(関数形式 / メモ化 / 依存を正しく調整)

useEffect(() => {
  setUser((prev) => ({ ...prev, name: 'Alice' }));
}, []);

パターン3:イベントハンドラをレンダー中に直接実行している

❌ NG

<button onClick={setCount(count + 1)}>Click</button>

onClick に渡しているのが関数ではなく「実行結果」なので、レンダーのたびに実行されます。

✅ OK

<button onClick={() => setCount(count + 1)}>Click</button>

パターン4:useMemo / useCallback 依存配列の誤り

依存配列を空にしたいのに、依存が変わり続ける書き方になっているパターン。

❌ NG

const fn = useCallback(() => {
  setState(Math.random()); // 依存が変わる → 毎回再生成 → 無限ループの原因に
}, [state]);

✅ OK

const fn = useCallback(() => {
  setState((v) => v + 1);
}, []);

パターン5:コンポーネントの props が毎回新しい参照値

親でオブジェクトや関数を inline 生成すると、子が毎回レンダリングされ、そこで更新処理が走るケース。

❌ NG(親)

<Child config={{ theme: 'dark' }} />

🎯 対策(親でメモ化)

const config = useMemo(() => ({ theme: 'dark' }), []);
<Child config={config} />;

まとめ:デバッグ時のチェックリスト

React の「Too many re-renders」が出たら、次を確認しましょう。

  • レンダー中に state 更新していないか?
  • useEffect の依存配列に “変わり続ける値” を入れていないか?
  • イベントハンドラを “実行結果” で渡していないか?
  • useMemo / useCallback の依存設定は正しいか?
  • 親から渡す props は毎回新しいオブジェクト・関数になっていないか?

これらを押さえておけば、無限再レンダーの大半は防げます。

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