MeWrite Docs

React Hook useEffect has a missing dependency

ReactのuseEffectで依存配列に不足がある場合の警告

概要

React Hook useEffect has a missing dependency は、useEffectの依存配列に、エフェクト内で使用している変数が含まれていない場合に表示されるESLint警告です。

警告メッセージ

React Hook useEffect has a missing dependency: 'fetchData'.
Either include it or remove the dependency array.
eslint(react-hooks/exhaustive-deps)
React Hook useEffect has missing dependencies: 'id' and 'name'.
Either include them or remove the dependency array.

原因

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
// 警告: fetchDataが依存配列にない
function UserProfile({ userId }) {
  const [user, setUser] = useState(null);

  const fetchData = async () => {
    const response = await fetch(`/api/users/${userId}`);
    const data = await response.json();
    setUser(data);
  };

  useEffect(() => {
    fetchData();  // fetchDataを使用
  }, []);  // 依存配列が空
}

解決策

1. 依存配列に追加

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
function UserProfile({ userId }) {
  const [user, setUser] = useState(null);

  const fetchData = useCallback(async () => {
    const response = await fetch(`/api/users/${userId}`);
    const data = await response.json();
    setUser(data);
  }, [userId]);  // userIdに依存

  useEffect(() => {
    fetchData();
  }, [fetchData]);  // fetchDataを依存配列に追加
}

2. エフェクト内で関数を定義

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
function UserProfile({ userId }) {
  const [user, setUser] = useState(null);

  useEffect(() => {
    // 関数をエフェクト内で定義
    const fetchData = async () => {
      const response = await fetch(`/api/users/${userId}`);
      const data = await response.json();
      setUser(data);
    };

    fetchData();
  }, [userId]);  // userIdのみ依存
}

3. useCallbackでメモ化

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
function UserProfile({ userId }) {
  const [user, setUser] = useState(null);

  // useCallbackでメモ化
  const fetchData = useCallback(async () => {
    const response = await fetch(`/api/users/${userId}`);
    const data = await response.json();
    setUser(data);
  }, [userId]);

  useEffect(() => {
    fetchData();
  }, [fetchData]);
}

4. 関数を外部に移動

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
// コンポーネント外に純粋関数として定義
async function fetchUser(userId) {
  const response = await fetch(`/api/users/${userId}`);
  return response.json();
}

function UserProfile({ userId }) {
  const [user, setUser] = useState(null);

  useEffect(() => {
    fetchUser(userId).then(setUser);
  }, [userId]);  // fetchUserは外部なので不要
}

よくあるパターン

オブジェクトの依存

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
// 警告: optionsは毎回新しいオブジェクト
function Component({ id }) {
  const options = { id, limit: 10 };

  useEffect(() => {
    fetchData(options);
  }, [options]);  // 無限ループの原因
}

// 解決策1: 個別の値を依存配列に
useEffect(() => {
  fetchData({ id, limit: 10 });
}, [id]);

// 解決策2: useMemoでメモ化
const options = useMemo(() => ({ id, limit: 10 }), [id]);

useEffect(() => {
  fetchData(options);
}, [options]);

イベントハンドラとの組み合わせ

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
function SearchComponent() {
  const [query, setQuery] = useState('');
  const [results, setResults] = useState([]);

  // 検索ロジックをuseCallbackで定義
  const search = useCallback(async () => {
    if (!query) return;
    const data = await fetchSearchResults(query);
    setResults(data);
  }, [query]);

  // 入力変更時に検索(デバウンス付き)
  useEffect(() => {
    const timer = setTimeout(search, 300);
    return () => clearTimeout(timer);
  }, [search]);

  return (
    <input value={query} onChange={e => setQuery(e.target.value)} />
  );
}

setStateは依存不要

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
function Counter() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    const timer = setInterval(() => {
      // setCountは安定しているので依存配列に不要
      setCount(c => c + 1);
    }, 1000);
    return () => clearInterval(timer);
  }, []);  // 空の依存配列でOK
}

ESLint警告を無効化(非推奨)

1
2
3
4
5
// 本当に必要な場合のみ使用
useEffect(() => {
  fetchData();
  // eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

無限ループの回避

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
// NG: 無限ループ
useEffect(() => {
  setData({ ...data, loaded: true });
}, [data]);  // dataが変わるたびに実行

// OK: 関数型更新
useEffect(() => {
  setData(prev => ({ ...prev, loaded: true }));
}, []);

// OK: 特定のプロパティのみ監視
useEffect(() => {
  if (!data.loaded) {
    setData(prev => ({ ...prev, loaded: true }));
  }
}, [data.loaded]);

関連エラー

関連エラー

React の他のエラー

最終更新: 2025-12-24