Reactでは1つのコンポーネントに対してuseEffectを複数設置できます。
ですが、現場でのレビューでは「副作用がまとまっておらず、読みにくい」「副作用が絡み合っていて解除漏れが怖い」など、設計判断に迷いが生まれがちです。

この記事では、「useEffectを複数に分けるか否か」の判断基準をレビュー観点から整理します。

よくある設計の分岐

1つにまとめたuseEffect
useEffect(() => {
  fetchData();
  const interval = setInterval(polling, 1000);
  window.addEventListener("resize", handleResize);

  return () => {
    clearInterval(interval);
    window.removeEventListener("resize", handleResize);
  };
}, []);
分けたuseEffect構造
useEffect(() => {
  fetchData();
}, []);

useEffect(() => {
  const interval = setInterval(polling, 1000);
  return () => clearInterval(interval);
}, []);

useEffect(() => {
  window.addEventListener("resize", handleResize);
  return () => window.removeEventListener("resize", handleResize);
}, []);

レビューとして問われるのは、「どちらが明確か」「どちらが安全か」です。

複数useEffectの利点と構造的意義

  • 目的ごとの副作用が分離されるため、読解が容易
  • 再実行やクリーンアップのトリガーが明確に制御できる
  • 依存配列の個別制御が可能になり、誤動作を避けられる
実行タイミングを明示できる
useEffect(() => {
  fetchData();
}, [userId]); // userIdの変更時のみ再実行

useEffect(() => {
  const timer = setInterval(poll, 1000);
  return () => clearInterval(timer);
}, []); // 初回だけ
コードレビュー
@Reviewer: 副作用が責務ごとに分離されており、それぞれの再実行条件が明示されています。意図しない再実行や副作用の衝突が防げる構造です。

依存配列の誤爆を防ぐ意味でも有効

問題例:1つにまとめて複数依存
useEffect(() => {
  fetchData();
  setThemeColor();
}, [userId, theme]);

// → userIdの変更でsetThemeColorも再実行されてしまう可能性

このように、依存配列を共通にしてしまうと、副作用が関係ないタイミングでも再実行されてしまうという問題が生じます。

useEffectの分割設計をレビューする際の観点

図解:複数useEffectによる副作用の分離

UML Diagram

統合的なルール:どのくらいに分けるのが適切か?

レビュー観点での目安
  • 副作用の再実行タイミングが異なるものは分ける
  • クリーンアップの責務が違うものは分ける
  • 目的や影響範囲が独立しているものは分ける

逆に、以下のような場合は1つにまとめてもよいです。

  • 複数処理が同時に走ることが前提(例:ログ取得とアクセス記録)
  • 再実行タイミングや依存が完全に一致している

まとめ

useEffectの分割は、ただのコーディングスタイルではありません。副作用のトリガー・責務・クリーンアップを構造的に分離するための設計判断です。

レビューアーとしては、「なぜ1つにしたのか」「なぜ分けたのか」を明確に読み取り、依存配列・再実行条件・解除責任の整合性を確認していくことが重要です。