React useEffectによるデータ取得 — パターンとベストプラクティス
ReactのuseEffectでデータを取得する方法を学びます。クリーンアップ、競合状態、AbortController、依存配列、非同期操作のベストプラクティスを網羅。
Effect Hooks
詳細な説明
useEffectによるデータ取得
useEffectはReact関数コンポーネントで副作用を実行するための主要なHookです。データ取得は最も一般的なユースケースの一つです。
基本的なデータ取得パターン
useEffect(() => {
let ignore = false;
async function fetchData() {
const response = await fetch(\`/api/users/\${userId}\`);
const data = await response.json();
if (!ignore) {
setUser(data);
}
}
fetchData();
return () => {
ignore = true;
};
}, [userId]);
クリーンアップ関数が重要な理由
クリーンアップがないと、競合状態のリスクがあります。フェッチが完了する前にユーザーが移動したりuserIdが変更された場合、アンマウントされたコンポーネントの状態を設定したり、古いデータを表示する可能性があります。
AbortControllerの使用
より堅牢なアプローチはAbortControllerを使用して進行中のリクエストをキャンセルします:
useEffect(() => {
const controller = new AbortController();
fetch(\`/api/users/\${userId}\`, { signal: controller.signal })
.then(r => r.json())
.then(data => setUser(data))
.catch(err => {
if (err.name !== "AbortError") setError(err);
});
return () => controller.abort();
}, [userId]);
依存配列のルール
- 空配列
[]:マウント時に一度だけフェッチ(componentDidMountに相当) - 依存関係あり
[userId]:userIdが変更されたときに再フェッチ - 配列なし:毎レンダリング後に実行(フェッチには通常不適切)
一般的な間違い
- asyncを直接渡す:
useEffect(async () => ...)はPromiseを返しますが、Reactはvoidまたはクリーンアップ関数を期待します。エフェクト内でasync呼び出しをラップしてください。 - 依存関係の欠落:依存関係を省略すると古いデータの原因になります。常にすべてのリアクティブ値を含めてください。
- 無限ループ:依存関係でもある状態を設定すると無限サイクルが発生します。
ユースケース
コンポーネントのマウント時や依存関係の変更時にAPIからデータを読み込む必要がある場合にuseEffectを使用します。外部ソースからのデータを表示するコンポーネントに不可欠です。