exhaustive-deps
Full Name in @eslint-react/eslint-plugin
@eslint-react/hooks-extra/exhaustive-depsFull Name in eslint-plugin-react-hooks-extra
react-hooks-extra/exhaustive-depsPresets
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:
setStatefunction fromuseStatedispatchfunction fromuseReducerrefobject fromuseRefstartTransitionfunction fromuseTransition- 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;
}