How to fix Missing dependency in useEffect: recommended linter config not found in React
This ESLint warning occurs when the exhaustive-deps rule is not properly configured or when dependencies used inside React hooks are not included in the dependency array, potentially causing stale closures and subtle bugs.
Quick fix
Fixes react-hooks/exhaustive-deps
npm list eslint-plugin-react-hooks- Install eslint-plugin-react-hooks if not already installed
- Configure the plugin in your ESLint config file
- Add missing dependencies to your dependency arrays
- Handle function dependencies with useCallback
npm list eslint-plugin-react-hooksMissing dependency in useEffect: recommended linter config not found
What this error means
The "react-hooks/exhaustive-deps" warning appears when ESLint's React Hooks plugin detects that you're using values inside hooks like useEffect, useMemo, or useCallback without including them in the dependency array. This rule is part of eslint-plugin-react-hooks, which is maintained by the React team to enforce the Rules of Hooks. When a value referenced inside these hooks isn't included in the dependency array, React won't re-run the effect or recalculate the value when that dependency changes, leading to stale closures. The component will continue using outdated values from previous renders, causing bugs that are often difficult to debug. The error message specifically about "recommended linter config not found" indicates that your ESLint configuration is either missing the React Hooks plugin entirely, or it's not properly configured to check for exhaustive dependencies in your effects and custom hooks.
Typical symptoms
- ESLint warning: "React Hook useEffect has a missing dependency"
- Effects using stale values from props or state
- Components not updating when expected
- Inconsistent behavior after state changes
- No linter warnings despite missing dependencies in hooks
- Custom hooks not being checked for dependency issues
Common causes
- ESLint plugin eslint-plugin-react-hooks is not installed in the project
- The exhaustive-deps rule is not enabled in ESLint configuration
- Dependencies are omitted from useEffect, useMemo, or useCallback dependency arrays
- Variables or functions used in hooks are declared outside without being memoized
- Custom hooks are not configured in additionalHooks setting
- ESLint configuration uses outdated format or incorrect plugin setup
How to fix "Missing dependency in useEffect: recommended linter config not found"
First, check if the plugin is installed in your project:
npm list eslint-plugin-react-hooksIf not installed, add it to your project:
npm install --save-dev eslint-plugin-react-hooksOr with yarn:
yarn add --dev eslint-plugin-react-hooksFor modern ESLint (9.0.0+) using flat config format, edit eslint.config.js:
import reactHooks from 'eslint-plugin-react-hooks';
export default [
{
plugins: {
'react-hooks': reactHooks
},
rules: {
'react-hooks/rules-of-hooks': 'error',
'react-hooks/exhaustive-deps': 'warn'
}
}
];For legacy ESLint configuration (.eslintrc.json):
{
"plugins": ["react-hooks"],
"rules": {
"react-hooks/rules-of-hooks": "error",
"react-hooks/exhaustive-deps": "warn"
}
}Or in .eslintrc.js:
module.exports = {
plugins: ['react-hooks'],
rules: {
'react-hooks/rules-of-hooks': 'error',
'react-hooks/exhaustive-deps': 'warn'
}
};Once the rule is configured, ESLint will warn about missing dependencies. Add all referenced values to the dependency array:
Before:
function MyComponent({ userId }) {
const [data, setData] = useState(null);
useEffect(() => {
fetchUserData(userId).then(setData);
}, []); // Missing dependency: userId
}After:
function MyComponent({ userId }) {
const [data, setData] = useState(null);
useEffect(() => {
fetchUserData(userId).then(setData);
}, [userId]); // Dependency added
}If you're passing functions as dependencies, wrap them in useCallback to prevent infinite re-renders:
Before:
function MyComponent() {
const handleClick = () => {
console.log('clicked');
};
useEffect(() => {
handleClick();
}, [handleClick]); // handleClick recreated every render
}After:
import { useCallback } from 'react';
function MyComponent() {
const handleClick = useCallback(() => {
console.log('clicked');
}, []);
useEffect(() => {
handleClick();
}, [handleClick]); // Stable reference
}Alternatively, move the function inside the effect if it's only used there:
function MyComponent() {
useEffect(() => {
const handleClick = () => {
console.log('clicked');
};
handleClick();
}, []);
}If you have custom hooks that should follow the same dependency rules, configure them using the additionalHooks option:
{
"rules": {
"react-hooks/exhaustive-deps": [
"warn",
{
"additionalHooks": "(useMyCustomEffect|useMyDataFetcher)"
}
]
}
}The value is a regex pattern matching the names of your custom hooks. For ESLint 6.1.1+, you can also use additionalEffectHooks in settings:
{
"settings": {
"react": {
"additionalEffectHooks": ["useMyCustomEffect"]
}
}
}After updating your ESLint configuration, restart your development tools:
VS Code:
- Open Command Palette (Cmd/Ctrl + Shift + P)
- Run "ESLint: Restart ESLint Server"
- Or reload the window: "Developer: Reload Window"
WebStorm/IntelliJ:
- File → Invalidate Caches / Restart
- Or simply restart the IDE
Command line:
npx eslint . --ext .js,.jsx,.ts,.tsxThis ensures your editor picks up the new ESLint configuration.
Advanced notes
Understanding Stale Closures
When dependencies are missing, effects capture values from the render when they were created. If those values change in later renders but the effect doesn't re-run, you get a "stale closure" - your effect is still using old values.
When to Disable the Rule
There are legitimate cases to disable the rule using // eslint-disable-next-line react-hooks/exhaustive-deps:
1. Intentionally running only once: When you truly want an effect to run only on mount, despite using external values
2. Using refs: When accessing ref.current values that intentionally don't trigger re-renders
3. Event handlers: When functions are only used for their latest behavior, not their closure
However, these cases are rare. Most of the time, the linter is correct and you should add the dependency.
Memoization Patterns
For objects and arrays, use useMemo to maintain stable references:
const options = useMemo(() => ({
method: 'POST',
headers: { 'Content-Type': 'application/json' }
}), []);
useEffect(() => {
fetch('/api', options);
}, [options]);Create React App Note
Projects created with Create React App include this plugin by default with the recommended configuration. If you ejected or are using a custom webpack setup, you'll need to configure it manually.
React 18+ and Concurrent Features
With React 18's concurrent rendering, stale closures can cause even more subtle issues. The exhaustive-deps rule becomes even more critical as effects may be interrupted and restarted, making proper dependency tracking essential for correctness.
Frequently asked questions
- What does "react-hooks/exhaustive-deps" mean?
- The "react-hooks/exhaustive-deps" warning appears when ESLint's React Hooks plugin detects that you're using values inside hooks like useEffect, useMemo, or useCallback without including them in the dependency array. This rule is part of eslint-plugin-react-hooks, which is maintained by the React team to enforce the Rules of Hooks. When a value referenced inside these hooks isn't included in the dependency array, React won't re-run the effect or recalculate the value when that dependency changes, leading to stale closures.
- How do I fix "react-hooks/exhaustive-deps"?
- This ESLint warning occurs when the exhaustive-deps rule is not properly configured or when dependencies used inside React hooks are not included in the dependency array, potentially causing stale closures and subtle bugs.
- What causes "react-hooks/exhaustive-deps"?
- ESLint plugin eslint-plugin-react-hooks is not installed in the project The exhaustive-deps rule is not enabled in ESLint configuration Dependencies are omitted from useEffect, useMemo, or useCallback dependency arrays
- Is the "react-hooks/exhaustive-deps" 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 exhaustive-deps rule documentation(Official Docs)
- 📖eslint-plugin-react-hooks npm package(Official Docs)
- 📖React Hooks ESLint plugin GitHub README(Official Docs)
- 📝
- 📝