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が変更されたときに再フェッチ
  • 配列なし:毎レンダリング後に実行(フェッチには通常不適切)

一般的な間違い

  1. asyncを直接渡すuseEffect(async () => ...)はPromiseを返しますが、Reactはvoidまたはクリーンアップ関数を期待します。エフェクト内でasync呼び出しをラップしてください。
  2. 依存関係の欠落:依存関係を省略すると古いデータの原因になります。常にすべてのリアクティブ値を含めてください。
  3. 無限ループ:依存関係でもある状態を設定すると無限サイクルが発生します。

ユースケース

コンポーネントのマウント時や依存関係の変更時にAPIからデータを読み込む必要がある場合にuseEffectを使用します。外部ソースからのデータを表示するコンポーネントに不可欠です。

試してみる — React Hooks Reference

フルツールを開く