logoESLint React
Rules

exhaustive-deps

Full Name in @eslint-react/eslint-plugin

@eslint-react/hooks-extra/exhaustive-deps

Full Name in eslint-plugin-react-hooks-extra

react-hooks-extra/exhaustive-deps

Presets

Not included in any preset.

Features

🔧

Description

Enforces that React hook dependency arrays contain all reactive values used in the callback.

When using hooks like useEffect, useMemo, or useCallback, the dependency array must include every reactive value referenced inside the callback. Missing dependencies can lead to stale closures and subtle bugs where the callback uses outdated values. Unnecessary dependencies can cause the hook to re-run more often than needed.

This rule checks the following built-in hooks: useEffect, useLayoutEffect, useInsertionEffect, useMemo, useCallback, and useImperativeHandle.

Stable values

The rule recognizes values that React guarantees to be stable across renders and does not require them in the dependency array:

  • setState function from useState
  • dispatch function from useReducer
  • ref object from useRef
  • startTransition function from useTransition
  • Module-level constants and imports

Autofix behavior

When missing or unnecessary dependencies are detected, the rule provides an automatic fix that:

  • Adds missing dependencies to the array, sorted alphabetically
  • Removes unnecessary dependencies from the array
  • Preserves existing valid dependencies

When the dependency array is not an array literal (e.g., a variable reference), the rule reports a diagnostic but does not provide an autofix.

Rule Options

type Options = {
  additionalHooks?: string;
};

additionalHooks

A regex pattern specifying custom hooks that accept dependency arrays. When provided, the rule applies dependency checking to hooks whose names match the pattern.

Default: not set (only built-in hooks are checked)

Examples

Passing

import { useEffect, useState } from "react";

function MyComponent({ id }) {
  const [data, setData] = useState(null);

  useEffect(() => {
    fetchData(id).then(setData);
  }, [id]);

  return <div>{data}</div>;
}

Passing

import { useEffect, useState, useRef } from "react";

function MyComponent({ value }) {
  const [count, setCount] = useState(0);
  const ref = useRef(null);

  // ✅ setState and ref are stable — no need to include them
  useEffect(() => {
    setCount(value);
    ref.current = value;
  }, [value]);

  return <div>{count}</div>;
}

Passing

import { useMemo } from "react";

const MULTIPLIER = 2;

function MyComponent({ value }) {
  // ✅ Module-level constants are stable
  const result = useMemo(() => value * MULTIPLIER, [value]);
  return <div>{result}</div>;
}

Failing

import { useEffect, useState } from "react";

function MyComponent({ id, name }) {
  const [data, setData] = useState(null);

  // 🔴 React Hook 'useEffect' has missing dependencies: 'name'.
  useEffect(() => {
    fetchData(id, name).then(setData);
  }, [id]);

  return <div>{data}</div>;
}

Failing

import { useEffect, useState } from "react";

function MyComponent({ id }) {
  const [data, setData] = useState(null);
  const [count, setCount] = useState(0);

  // 🔴 React Hook 'useEffect' has unnecessary dependencies: 'count'.
  useEffect(() => {
    fetchData(id).then(setData);
  }, [id, count]);

  return <div>{data}</div>;
}

Failing

import { useCallback } from "react";

function MyComponent({ onClick }) {
  const deps = [onClick];

  // 🔴 React Hook 'useCallback' was passed a dependency list that is not an array literal.
  const handler = useCallback(() => {
    onClick();
  }, deps);

  return <button onClick={handler}>Click</button>;
}

Failing

import { useEffect } from "react";

function MyComponent({ obj }) {
  // 🔴 React Hook 'useEffect' has missing dependencies: 'obj.property'.
  useEffect(() => {
    console.log(obj.property);
  }, []);

  return null;
}

Examples with additionalHooks

Configuration

{
  "react-hooks-extra/exhaustive-deps": ["warn", {
    "additionalHooks": "useCustomEffect|useMyMemo"
  }]
}

Failing

function MyComponent({ id }) {
  // 🔴 React Hook 'useCustomEffect' has missing dependencies: 'id'.
  useCustomEffect(() => {
    fetchData(id);
  }, []);

  return null;
}

Passing

function MyComponent({ id }) {
  // ✅ All dependencies are present
  useCustomEffect(() => {
    fetchData(id);
  }, [id]);

  return null;
}

Implementation

Further Reading

On this page