【ITニュース解説】When Not to Use useEffect in React

2025年09月06日に「Dev.to」が公開したITニュース「When Not to Use useEffect in React」について初心者にもわかりやすいように丁寧に解説しています。

作成日: 更新日:

ITニュース概要

ReactのuseEffectは外部システムとの同期に使うが、安易な使用は非効率やエラーの原因となる。PropsやStateに基づくState更新、高コスト計算のキャッシュ、Props変更時のStateリセット/調整、イベントハンドラでのロジック共有、POSTリクエスト、計算チェーン、アプリ初期化、親コンポーネントへの通知、データ渡し、外部ストア購読、データ取得など、useEffectが不適切なケースとその解決策を解説。

出典: When Not to Use useEffect in React | Dev.to公開日:

ITニュース解説

ReactのuseEffectは、コンポーネントを外部システムと連携させるための強力なツールだ。しかし、useEffectの不適切な使用はパフォーマンス低下やエラーの原因となるため、注意が必要となる。

まず、propsやstateの変化に基づいてstateを更新する場合、useEffectは不要であることが多い。Reactはstateが変更されるたびに再レンダリングを行うため、useEffectを使ってstateを更新するのは冗長になる。例えば、firstNamelastNameが変わるたびにfullNameを更新したい場合、useEffectを使う代わりに、レンダリング中にfullNameを計算する方が効率的だ。

次に、計算コストの高い処理の結果をキャッシュする場合は、useMemoフックを利用するのが良い。useMemoは、依存配列に指定された値が変更された場合にのみ計算を再実行するため、不要な再レンダリングを避けることができる。例えば、todosリストをpropsのfilterに基づいてフィルタリングする場合、useMemoを使うことで、filterが変わった時だけフィルタリング処理が実行される。

propsの変化に応じてstateをリセットする必要がある場合も、useEffectの使い方が重要となる。例えば、userIdが変わるたびにコメントをリセットしたい場合、単純にuseEffectを使うと、Reactが最初にコメントをレンダリングしてからリセットするため、一瞬古いコメントが表示されてしまう。この問題を解決するには、親コンポーネントでuserIdをkeyとして渡すことで、ReactがProfileコンポーネントを独立したものとして扱い、userIdが変わるたびにコンポーネント全体がリセットされるようにする。

propsの変化に応じてstateの一部だけを調整したい場合は、useEffectは避けるべきだ。例えば、items propsが変わった時にselectionをリセットし、isReverseはそのままにしたい場合、useEffectを使うと、Reactが最初にselectionをレンダリングしてからnullに設定してしまう。この場合、追加のstateに前の値を保存し、propsが変更されたかどうかを比較するよりも、レンダリング中に直接stateを計算する方が効率的だ。

イベントハンドラ間でロジックを共有する場合も、useEffectの使用は避けるべきだ。例えば、ユーザーが「購入」ボタンまたは「チェックアウト」ボタンをクリックしたときに通知を表示したい場合、useEffectproduct.isInCartを監視すると、ページ訪問時やリロード時にも通知が表示されてしまう。通知はユーザーのアクションの結果としてのみ表示されるべきなので、イベントハンドラ内で通知をトリガーする。

POSTリクエストの送信も、状況に応じてuseEffectとイベントハンドラを使い分ける必要がある。例えば、ページのマウント時に分析イベントを送信する場合は、useEffectが適切だ。しかし、フォームの送信など、ユーザーのクリックに応じてPOSTリクエストを送信する場合は、イベントハンドラ内で処理するべきだ。

複数のuseEffectフックを連鎖的に使用することも避けるべきだ。stateの変化に応じて別のuseEffectがトリガーされるようなコードは、非効率であるだけでなく、エラーが発生しやすくなる。イベントハンドラ内で状態を計算および調整する方が、よりシンプルで予測可能なコードになる。ただし、ドロップダウンメニューの表示など、useEffectの連鎖がどうしても必要な場合もある。

アプリケーションの初期化処理をuseEffectで行う場合、ReactのStrict Modeによって処理が2回実行される可能性があるため、注意が必要だ。初期化が一度だけ行われるように、フラグ変数を使用するなどの対策が必要となる。

子コンポーネントから親コンポーネントにstateの変更を通知する場合、useEffectを使うのは不適切だ。状態は最初にレンダリングされてからuseEffectが実行されるため、親コンポーネントへの通知が遅れてしまう。代わりに、stateを更新する関数を作成し、それを両方のイベントハンドラで呼び出すか、stateを親コンポーネントに持ち上げて管理する。

子コンポーネントから親コンポーネントにデータを渡すためにuseEffectを使うのは、Reactのデータフローの原則に反する。データは通常、親から子に渡されるべきだ。

外部ストアのデータにサブスクライブする場合は、useEffectを使用するのが一般的だが、Reactは外部ストアにサブスクライブするための専用のフックであるuseSyncExternalStoreを提供している。これを使うことで、useEffectで可変データを手動でサブスクライブするよりもエラーが発生しにくくなる。

データのフェッチに関しても、useEffectを使うべきだ。例えば、検索クエリやページ番号が変更されたときにデータをフェッチするSearchResultコンポーネントでは、useEffectを使ってフェッチ処理を行うのが適切だ。ただし、ユーザーが高速で検索クエリを入力する場合、競合状態が発生する可能性がある。この問題を解決するには、クリーンアップ関数を使用して、古いレスポンスを無視するようにする必要がある。

useEffectは非常に便利なフックだが、その必要性と適切な使用方法を理解することが重要だ。