Reactコンポーネントでは、ページ遷移直後や初回描画時にのみ副作用を実行したい場面があります。その場合、useEffect に空の依存配列 [] を与えることで初回マウント時のみ実行される副作用を記述できます。

一方で、レビューの現場では以下のような誤用や曖昧な設計に直面します:

  • 「本当に初回だけでよいのか」が意図として明示されていない
  • ページ遷移後にも再実行されることを前提に設計されていない
  • クライアントサイドルーティングとの整合性が考慮されていない

本記事では、初回マウントや画面遷移に特化した useEffect の構造判断について、レビューアーの視点から整理していきます。

useEffect(() => {}, []) の意味と責任範囲

初回だけの副作用構造
useEffect(() => {
  console.log("component mounted");
}, []);

この構造は、「マウント時に一度だけ実行される処理」を表現します。具体的には次のような用途に使われます:

  • ページ初期化処理
  • クライアントサイドAPIのプリフェッチ
  • 初回ログ出力や解析イベント送信
空依存配列の意味

useEffect(fn, []) は、Reactの描画サイクルにおいてマウント時(初回のDOM挿入後)にのみ fn が実行される構造です。再描画や依存変数の変化には反応しません。

よくある設計ミス:本当に「初回だけ」でよいのか?

設計意図が不明な初回Effect
useEffect(() => {
  fetch("/api/user");
}, []);
コードレビュー
@Reviewer: 初回のみAPIを呼ぶ構造ですが、ユーザーIDやページコンテキストが変わった際にも再取得が必要な仕様であれば、この設計は不適切です。依存条件を明示してください。

「初回だけでよい」のか、「ページが切り替わるたびに必要」なのか、「条件に応じて必要」なのか。これをレビュー時に明示的に仕様と照らし合わせる必要があります。

クライアントルーティングとの整合性

SPAでReact Routerなどを使っている場合、「マウント=ページ遷移後」となるケースと、DOMが入れ替わらずルートだけが変わるケースがあります。

useLocationでのパス依存
const location = useLocation();

useEffect(() => {
  console.log("path changed:", location.pathname);
}, [location.pathname]);
コードレビュー
@Reviewer: ルーティングによって再描画されない構造の中で、`pathname` の変化に応じた副作用を設計することで、「画面遷移後の初回」としての責務を正しく分離できます。

このように、「初回=マウント時」ではなく、「初回=ルーティング上の意味」として定義するケースも増えており、レビューアーとしては依存の意味とユーザーの画面単位での文脈を見極める必要があります。

初期化処理を意図ごとに分離する設計

初回マウントに限る処理

マウント時だけの構造
useEffect(() => {
  console.log("初回のみ");
}, []);

条件付きで再実行される構造(例:userIdの変更時)

条件に応じた初期化
useEffect(() => {
  initializeUser(userId);
}, [userId]);

ルーティング変更に伴う初期化処理

React Routerと連携
const location = useLocation();

useEffect(() => {
  initPageFor(location.pathname);
}, [location.pathname]);

可視化:初回Effectとルーティング依存の違い

UML Diagram

カスタムHookで初期化処理を責務ごとに分離する

usePageInit.ts
export function usePageInit(path: string, initFn: () => void) {
  const location = useLocation();

  useEffect(() => {
    if (location.pathname === path) {
      initFn();
    }
  }, [location.pathname]);
}
利用側
usePageInit("/dashboard", () => {
  console.log("dashboard初期化");
});
コードレビュー
@Reviewer: 特定のページに限定した初期化処理がHookで明示されており、構造上の責務分離が明確です。再利用性・テスト性ともに高く保たれています。

レビュー観点チェックリスト

「初回だけ」のつもりで書かれた useEffect が、意図せず複数回実行されたり、逆に再実行されなかったりするケースは非常に多く見られます。レビューアーは常に構造の設計意図と実行タイミングが一致しているかを見極め、必要に応じて依存の見直しや責務分離を提案する役割を担います。