useEffect の基本:依存関係とクリーンアップ
レンダリング後に副作用を実行し、依存配列で再実行のタイミングを制御し、メモリリークを防ぐためにクリーンアップ関数を返します。
「useEffect の基本:依存関係とクリーンアップ」はCoddyKit上の無料Frontend Academyレッスンです。 これはレッスン1/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはFrontend Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Frontend Academyコースには全4レッスンが含まれています。
useEffect とは
useEffect は、React がレンダリングした後に副作用を実行します。副作用には、データの取得、イベントの購読、タイマーの設定、外部 API とのやり取りなどがあります。エフェクトはレンダリング中ではなく、ペイント後に実行されます。
基本構文
useEffect(effect, deps?)。デフォルトでは、エフェクト関数はすべてのレンダリング後に実行されます。実行タイミングを制御するには、依存配列を指定します。
import { useEffect } from 'react';
function Component() {
useEffect(() => {
console.log('Ran after every render');
});
}依存配列によるエフェクトの実行タイミングの制御
空の配列 []:マウント後に 1 回だけ実行します。空でない配列 [a, b]:a または b が変化したときに実行します。配列なし:すべてのレンダリング後に実行します(通常は望ましくありません)。
// Run once on mount:
useEffect(() => {
fetchInitialData();
}, []);
// Run when userId changes:
useEffect(() => {
fetchUser(userId);
}, [userId]);
// Run after every render (usually a bug):
useEffect(() => {
trackPageView();
});クリーンアップ関数
useEffect から関数を返すと、クリーンアップを実行できます。イベントリスナーの削除、購読のキャンセル、タイマーの消去などに使用します。クリーンアップは次のエフェクトの前とアンマウント時に実行されます。
useEffect(() => {
const handleResize = () => setWidth(window.innerWidth);
window.addEventListener('resize', handleResize);
// Cleanup: remove listener when effect re-runs or component unmounts
return () => {
window.removeEventListener('resize', handleResize);
};
}, []);依存関係における古いクロージャ
エフェクトは、作成された時点で参照していた値をクロージャとして保持します。依存配列に含めずにエフェクト内で state や prop の値を読み取ると、古い値が使われます。ESLint の exhaustive-deps ルールでこの問題を検出できます。
ESLint の exhaustive-deps ルール
react-hooks/exhaustive-deps ESLint ルールは、エフェクトの依存関係が不足している場合に警告します。古い依存関係はバグの原因になるため、ほとんどの場合はこのルールの提案に従うのが正しい対応です。
useEffect と useLayoutEffect の比較
useEffect はブラウザーによるペイントの後に実行されます。useLayoutEffect は DOM の変更直後、ペイント前に同期的に実行されます。視覚的なちらつきを避けるため、DOM の寸法を読み取る場合は useLayoutEffect を使用します。
複数のエフェクト
関係のない処理を分離するには、useEffect を複数回呼び出します。各エフェクトで、それぞれ独自の依存配列とクリーンアップ処理を指定できます。
// Separate effects for separate concerns:
useEffect(() => { document.title = `${count} items`; }, [count]);
useEffect(() => {
const sub = wsClient.subscribe(onMessage);
return () => sub.unsubscribe();
}, []);競合状態 — ignore フラグ
props に基づいてエフェクトでデータを取得する場合、先に開始したリクエストが後から開始したリクエストより後に完了することがあります。クリーンアップフラグを使用して、古いレスポンスを無視します。
useEffect(() => {
let ignore = false;
async function load() {
const data = await fetchUser(userId);
if (!ignore) setUser(data); // only update if not cleaned up
}
load();
return () => { ignore = true; };
}, [userId]);Strict Mode によるエフェクトの二重実行
React 18 の Strict Mode は、クリーンアップに関するバグを見つけるため、開発中にコンポーネントをマウント、アンマウント、再マウントします。そのためエフェクトは 2 回実行されます。これは意図的な動作であり、クリーンアップの不足を検出するのに役立ちます。
useEffect を使用しない場合
次の目的では useEffect を使用しないでください。1) props から state を導出する(レンダリング中に計算します)、2) prop の変更時に state をリセットする(key prop を使用します)、3) 無条件に state を更新する(ループの原因になります)。判断に迷ったら、「このコードはユーザーイベントまたは外部システムに反応するものか」と考えてみてください。
確認問題
useEffect のクリーンアップ関数はいつ実行されますか?
まとめ:useEffect
副作用はレンダリング後に実行します。空の依存配列 = マウント時に 1 回だけ実行します。依存配列 = 特定の変更時に実行します。メモリリークを防ぐには、クリーンアップ関数を返します。処理を分離するには、複数のエフェクトを使用します。ignore フラグで古い fetch レスポンスを無視できます。Strict Mode はクリーンアップをテストするためにエフェクトを 2 回実行します。レンダリング中に計算できる派生値や state には useEffect を使用しないでください。
よくある質問
「useEffect の基本:依存関係とクリーンアップ」レッスンは無料ですか?
はい。「useEffect の基本:依存関係とクリーンアップ」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Frontend Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Frontend Academyコースには全4レッスンが含まれています。
「useEffect の基本:依存関係とクリーンアップ」で何を学びますか?
レンダリング後に副作用を実行し、依存配列で再実行のタイミングを制御し、メモリリークを防ぐためにクリーンアップ関数を返します。 ブラウザで直接実行するハンズオンコードでFrontend Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
Frontend Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのFrontend Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン1/4です。
「useEffect の基本:依存関係とクリーンアップ」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このFrontend Academyレッスンでコードを書いて実行できますか?
はい。すべてのFrontend Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- useEffect の基本:依存関係とクリーンアップ
- マウント時のデータ取得
- ローディング状態とエラー状態の処理
- クリーンアップのための AbortController