How to fix The dependency list of this hook is missing entries in React
This ESLint warning occurs when you use variables, props, or state inside hooks like useEffect, useCallback, or useMemo without including them in the dependency array. Missing dependencies can cause stale closures where your hook uses outdated values, leading to subtle bugs that are hard to debug.
Quick fix
Fixes The dependency list of this hook is missing entries
Line 12:6: React Hook useEffect has a missing dependency: 'userId'.
Either include it or remove the dependency array react-hooks/exhaustive-deps- Identify the missing dependency from the ESLint warning message
- Add the missing dependency to the dependency array
- Wrap functions in useCallback to stabilize their reference
- Move variable or function declarations inside the hook
Line 12:6: React Hook useEffect has a missing dependency: 'userId'.Either include it or remove the dependency array react-hooks/exhaustive-depsThe dependency list of this hook is missing entries
What this error means
The react-hooks/exhaustive-deps ESLint rule enforces that all values referenced inside React hooks are included in their dependency arrays. When a variable, prop, or state value is used inside useEffect, useCallback, useMemo, or other hooks but not listed in the dependency array, ESLint flags it. This rule exists to prevent stale closures - a situation where your hook "remembers" old values instead of using current ones. React hooks rely on the dependency array to know when to re-run effects or recalculate memoized values. If a dependency is missing, React won't re-run the hook when that value changes, causing your app to use outdated data and behave unpredictably.
Typical symptoms
- ESLint warning: "React Hook useEffect has a missing dependency" in your editor or terminal
- Component behavior doesn't update when props or state change
- Effects running with stale data from previous renders
- Callbacks or memoized values using outdated values instead of current ones
- Unexpected behavior where user interactions don't trigger expected updates
- Console shows the ESLint warning: "The 'variableName' variable makes dependencies of useEffect Hook change on every render"
- Build process fails if ESLint is configured to treat warnings as errors
Common causes
- Using props, state, or context values inside useEffect without adding them to the dependency array
- Referencing functions defined in the component body inside hooks without wrapping them in useCallback
- Using variables from the outer scope inside useCallback or useMemo without listing them as dependencies
- Accessing object properties inside hooks while only including the parent object in dependencies, causing React to miss property changes
- Using external imported functions or constants that actually change between renders but appear static
- Copying values from props or state into local variables and only including the local variable in dependencies
- Intentionally omitting dependencies to create "run once" effects, which ESLint correctly flags as potentially buggy
How to fix "The dependency list of this hook is missing entries"
Read the complete ESLint warning in your terminal or editor. It will tell you exactly which variable is missing from the dependency array. Look for messages like: "React Hook useEffect has a missing dependency: 'count'. Either include it or remove the dependency array."
Example warning:
Line 12:6: React Hook useEffect has a missing dependency: 'userId'.
Either include it or remove the dependency array react-hooks/exhaustive-depsThe most straightforward fix is to add the missing variable to the dependency array. This ensures your hook re-runs whenever that value changes.
// BEFORE - ESLint warning
function UserProfile({ userId }) {
const [user, setUser] = useState(null);
useEffect(() => {
fetchUser(userId).then(setUser);
}, []); // Missing userId dependency
return <div>{user?.name}</div>;
}
// AFTER - Fixed
function UserProfile({ userId }) {
const [user, setUser] = useState(null);
useEffect(() => {
fetchUser(userId).then(setUser);
}, [userId]); // userId added to dependencies
return <div>{user?.name}</div>;
}Most modern IDEs with ESLint integration will offer an auto-fix option to add missing dependencies automatically.
If the missing dependency is a function defined in your component, wrap it in useCallback. This prevents the function from being recreated on every render, avoiding infinite loops.
// BEFORE - Function recreated every render
function SearchComponent({ apiEndpoint }) {
const [results, setResults] = useState([]);
const searchItems = (query) => {
fetch(apiEndpoint + query).then(r => r.json()).then(setResults);
};
useEffect(() => {
searchItems("default");
}, [searchItems]); // searchItems changes every render - infinite loop!
return <div>{results.length} results</div>;
}
// AFTER - Function memoized with useCallback
function SearchComponent({ apiEndpoint }) {
const [results, setResults] = useState([]);
const searchItems = useCallback((query) => {
fetch(apiEndpoint + query).then(r => r.json()).then(setResults);
}, [apiEndpoint]); // Only recreate when apiEndpoint changes
useEffect(() => {
searchItems("default");
}, [searchItems]); // Safe - searchItems reference is stable
return <div>{results.length} results</div>;
}If a variable or function is only used inside one hook, move its declaration inside that hook. This removes it from the dependency requirements entirely.
// BEFORE - External variable requires dependency
function Timer() {
const [seconds, setSeconds] = useState(0);
const interval = 1000;
useEffect(() => {
const timer = setInterval(() => {
setSeconds(s => s + 1);
}, interval);
return () => clearInterval(timer);
}, [interval]); // interval dependency required
return <div>{seconds}s</div>;
}
// AFTER - Constant moved inside effect
function Timer() {
const [seconds, setSeconds] = useState(0);
useEffect(() => {
const interval = 1000; // Moved inside
const timer = setInterval(() => {
setSeconds(s => s + 1);
}, interval);
return () => clearInterval(timer);
}, []); // No dependencies needed
return <div>{seconds}s</div>;
}When your effect only needs the previous state value to calculate the next one, use the functional form of setState. This removes the state variable from the dependency array.
// BEFORE - count is a dependency
function Counter({ increment }) {
const [count, setCount] = useState(0);
useEffect(() => {
const timer = setInterval(() => {
setCount(count + increment); // Uses current count
}, 1000);
return () => clearInterval(timer);
}, [count, increment]); // count causes effect to restart constantly
return <div>{count}</div>;
}
// AFTER - Functional update removes count dependency
function Counter({ increment }) {
const [count, setCount] = useState(0);
useEffect(() => {
const timer = setInterval(() => {
setCount(prev => prev + increment); // Uses previous value
}, 1000);
return () => clearInterval(timer);
}, [increment]); // Only increment needed as dependency
return <div>{count}</div>;
}If a value never changes or doesn't depend on props/state, move it outside the component. Constants, utility functions, and configuration objects can be declared at the module level.
// BEFORE - Function inside component
function DataTable({ data }) {
const formatDate = (date) => new Date(date).toLocaleDateString();
const formattedData = useMemo(() => {
return data.map(item => ({
...item,
date: formatDate(item.date)
}));
}, [data, formatDate]); // formatDate is a dependency
return <table>{/* render formattedData */}</table>;
}
// AFTER - Function extracted outside
const formatDate = (date) => new Date(date).toLocaleDateString();
function DataTable({ data }) {
const formattedData = useMemo(() => {
return data.map(item => ({
...item,
date: formatDate(item.date)
}));
}, [data]); // formatDate not needed - it's stable
return <table>{/* render formattedData */}</table>;
}Instead of depending on an entire object, destructure and depend only on the specific properties you use. This prevents unnecessary re-runs when unrelated properties change.
// BEFORE - Depends on entire user object
function UserGreeting({ user }) {
useEffect(() => {
console.log(`Hello ${user.name}`);
}, [user]); // Re-runs when any user property changes
return <div>Welcome {user.name}</div>;
}
// AFTER - Depends only on name property
function UserGreeting({ user }) {
const { name } = user;
useEffect(() => {
console.log(`Hello ${name}`);
}, [name]); // Only re-runs when name changes
return <div>Welcome {name}</div>;
}As a last resort, you can disable the ESLint rule for a specific line using a comment. However, this should be rare and well-documented, as it can hide real bugs.
function AnalyticsTracker() {
useEffect(() => {
// This should only run once on mount to initialize analytics
initializeAnalytics();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []); // Intentionally empty - we want this to run only once
return null;
}Before disabling, ask yourself: "What breaks if I add the dependency?" If adding it causes problems, the real issue is likely in your code structure, not the ESLint rule.
Advanced notes
The exhaustive-deps rule is one of the most valuable ESLint rules for React developers because it catches bugs that are extremely difficult to debug in production. Stale closures can cause intermittent bugs that only appear under specific user interaction patterns. In React 18+, the new useEffectEvent hook (currently experimental) is designed to solve cases where you need to reference values without adding them as dependencies. For complex dependencies like objects or arrays, consider using deep comparison hooks from libraries like react-use or ahooks if you truly need to compare values rather than references. When working with third-party libraries, some may not follow React hooks best practices, causing unavoidable exhaustive-deps warnings. In these cases, wrapping the library call in your own hook with proper dependencies is often the solution. The React team intentionally made this rule strict because the alternative - allowing missing dependencies - leads to subtle timing bugs that can go unnoticed for months. If you find yourself frequently fighting this rule, it often indicates that your component is doing too much and would benefit from being split into smaller, more focused components.
Frequently asked questions
- What does "The dependency list of this hook is missing entries" mean?
- The react-hooks/exhaustive-deps ESLint rule enforces that all values referenced inside React hooks are included in their dependency arrays. When a variable, prop, or state value is used inside useEffect, useCallback, useMemo, or other hooks but not listed in the dependency array, ESLint flags it. This rule exists to prevent stale closures - a situation where your hook "remembers" old values instead of using current ones.
- How do I fix "The dependency list of this hook is missing entries"?
- This ESLint warning occurs when you use variables, props, or state inside hooks like useEffect, useCallback, or useMemo without including them in the dependency array. Missing dependencies can cause stale closures where your hook uses outdated values, leading to subtle bugs that are hard to debug.
- What causes "The dependency list of this hook is missing entries"?
- Using props, state, or context values inside useEffect without adding them to the dependency array Referencing functions defined in the component body inside hooks without wrapping them in useCallback Using variables from the outer scope inside useCallback or useMemo without listing them as dependencies
- Is the "The dependency list of this hook is missing entries" error serious?
- It is a medium-severity error โ more of a blocker than a risk. The steps above resolve it.
Official resources & further reading
- ๐React Official Documentation
- ๐React official exhaustive-deps documentation(Official Docs)
- ๐
- ๐
- ๐