logo by @sawaratsuki1004
React
v19.2
Learn
Reference
Community
Blog

Is this page useful?

في هذه الصفحة

  • Overview
  • Rule Details
  • Common Violations
  • Invalid
  • Valid
  • Troubleshooting
  • Adding a function dependency causes infinite loops
  • Running an effect only once
  • Options

    react@19.2

  • نظرة عامة
  • Hooks
    • useActionState
    • useCallback
    • useContext
    • useDebugValue
    • useDeferredValue
    • useEffect
    • useEffectEvent
    • useId
    • useImperativeHandle
    • useInsertionEffect
    • useLayoutEffect
    • useMemo
    • useOptimistic
    • useReducer
    • useRef
    • useState
    • useSyncExternalStore
    • useTransition
  • المكونات
    • <Fragment> (<>)
    • <Profiler>
    • <StrictMode>
    • <Suspense>
    • <Activity>
    • <ViewTransition> - This feature is available in the latest Canary version of React
  • APIs
    • act
    • addTransitionType - This feature is available in the latest Canary version of React
    • cache
    • cacheSignal
    • captureOwnerStack
    • createContext
    • lazy
    • memo
    • startTransition
    • use
    • experimental_taintObjectReference - This feature is available in the latest Experimental version of React
    • experimental_taintUniqueValue - This feature is available in the latest Experimental version of React
  • react-dom@19.2

  • Hooks
    • useFormStatus
  • المكونات (Components)
    • Common (e.g. <div>)
    • <form>
    • <input>
    • <option>
    • <progress>
    • <select>
    • <textarea>
    • <link>
    • <meta>
    • <script>
    • <style>
    • <title>
  • APIs
    • createPortal
    • flushSync
    • preconnect
    • prefetchDNS
    • preinit
    • preinitModule
    • preload
    • preloadModule
  • Client APIs
    • createRoot
    • hydrateRoot
  • Server APIs
    • renderToPipeableStream
    • renderToReadableStream
    • renderToStaticMarkup
    • renderToString
    • resume
    • resumeToPipeableStream
  • Static APIs
    • prerender
    • prerenderToNodeStream
    • resumeAndPrerender
    • resumeAndPrerenderToNodeStream
  • React Compiler

  • الإعدادات (Configuration)
    • compilationMode
    • gating
    • logger
    • panicThreshold
    • target
  • Directives
    • "use memo"
    • "use no memo"
  • تصريف المكتبات (Compiling Libraries)
  • React DevTools

  • React Performance tracks
  • eslint-plugin-react-hooks

  • Lints
    • exhaustive-deps
    • rules-of-hooks
    • component-hook-factories
    • config
    • error-boundaries
    • gating
    • globals
    • immutability
    • incompatible-library
    • preserve-manual-memoization
    • purity
    • refs
    • set-state-in-effect
    • set-state-in-render
    • static-components
    • unsupported-syntax
    • use-memo
  • قواعد React (Rules of React)

  • نظرة عامة (Overview)
    • Components و Hooks يجب أن تكون Pure
    • React تستدعي Components و Hooks
    • قواعد Hooks
  • React Server Components

  • Server Components
  • Server Functions
  • Directives
    • 'use client'
    • 'use server'
  • Legacy APIs

  • Legacy React APIs
    • Children
    • cloneElement
    • Component
    • createElement
    • createRef
    • forwardRef
    • isValidElement
    • PureComponent
مرجع API
Lints

exhaustive-deps

Validates that dependency arrays for React hooks contain all necessary dependencies.

Rule Details

React hooks like useEffect, useMemo, and useCallback accept dependency arrays. 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. This causes stale closures where the hook uses outdated values.

Common Violations

This error often happens when you try to “trick” React about dependencies to control when an effect runs. Effects should synchronize your component with external systems. The dependency array tells React which values the effect uses, so React knows when to re-synchronize.

If you find yourself fighting with the linter, you likely need to restructure your code. See Removing Effect Dependencies to learn how.

Invalid

Examples of incorrect code for this rule:

// ❌ Missing dependency useEffect(() => { console.log(count); }, []); // Missing 'count' // ❌ Missing prop useEffect(() => { fetchUser(userId); }, []); // Missing 'userId' // ❌ Incomplete dependencies useMemo(() => { return items.sort(sortOrder); }, [items]); // Missing 'sortOrder'

Valid

Examples of correct code for this rule:

// ✅ All dependencies included useEffect(() => { console.log(count); }, [count]); // ✅ All dependencies included useEffect(() => { fetchUser(userId); }, [userId]);

Troubleshooting

Adding a function dependency causes infinite loops

You have an effect, but you’re creating a new function on every render:

// ❌ Causes infinite loop const logItems = () => { console.log(items); }; useEffect(() => { logItems(); }, [logItems]); // Infinite loop!

In most cases, you don’t need the effect. Call the function where the action happens instead:

// ✅ Call it from the event handler const logItems = () => { console.log(items); }; return <button onClick={logItems}>Log</button>; // ✅ Or derive during render if there's no side effect items.forEach(item => { console.log(item); });

If you genuinely need the effect (for example, to subscribe to something external), make the dependency stable:

// ✅ useCallback keeps the function reference stable const logItems = useCallback(() => { console.log(items); }, [items]); useEffect(() => { logItems(); }, [logItems]); // ✅ Or move the logic straight into the effect useEffect(() => { console.log(items); }, [items]);

Running an effect only once

You want to run an effect once on mount, but the linter complains about missing dependencies:

// ❌ Missing dependency useEffect(() => { sendAnalytics(userId); }, []); // Missing 'userId'

Either include the dependency (recommended) or use a ref if you truly need to run once:

// ✅ Include dependency useEffect(() => { sendAnalytics(userId); }, [userId]); // ✅ Or use a ref guard inside an effect const sent = useRef(false); useEffect(() => { if (sent.current) { return; } sent.current = true; sendAnalytics(userId); }, [userId]);

Options

You can configure custom effect hooks using shared ESLint settings (available in eslint-plugin-react-hooks 6.1.1 and later):

{ "settings": { "react-hooks": { "additionalEffectHooks": "(useMyEffect|useCustomEffect)" } } }

  • additionalEffectHooks: Regex pattern matching custom hooks that should be checked for exhaustive dependencies. This configuration is shared across all react-hooks rules.

For backward compatibility, this rule also accepts a rule-level option:

{ "rules": { "react-hooks/exhaustive-deps": ["warn", { "additionalHooks": "(useMyCustomHook|useAnotherHook)" }] } }

  • additionalHooks: Regex for hooks that should be checked for exhaustive dependencies. Note: If this rule-level option is specified, it takes precedence over the shared settings configuration.
السابقLints
التاليrules-of-hooks

Copyright © Meta Platforms, Inc
no uwu plz
uwu?
Logo by@sawaratsuki1004
تعلم React
بداية سريعة
التثبيت
وصف واجهة المستخدم (UI)
إضافة التفاعلية
إدارة State
مخارج الطوارئ
مرجع API
React APIs
React DOM APIs
المجتمع
ميثاق السلوك
تعرف على الفريق
المساهمون في التوثيق
شكر وتقدير
المزيد
المدونة
React Native
الخصوصية
الشروط
// ❌ Missing dependency
useEffect(() => {
console.log(count);
}, []); // Missing 'count'

// ❌ Missing prop
useEffect(() => {
fetchUser(userId);
}, []); // Missing 'userId'

// ❌ Incomplete dependencies
useMemo(() => {
return items.sort(sortOrder);
}, [items]); // Missing 'sortOrder'
// ✅ All dependencies included
useEffect(() => {
console.log(count);
}, [count]);

// ✅ All dependencies included
useEffect(() => {
fetchUser(userId);
}, [userId]);
// ❌ Causes infinite loop
const logItems = () => {
console.log(items);
};

useEffect(() => {
logItems();
}, [logItems]); // Infinite loop!
// ✅ Call it from the event handler
const logItems = () => {
console.log(items);
};

return <button onClick={logItems}>Log</button>;

// ✅ Or derive during render if there's no side effect
items.forEach(item => {
console.log(item);
});
// ✅ useCallback keeps the function reference stable
const logItems = useCallback(() => {
console.log(items);
}, [items]);

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

// ✅ Or move the logic straight into the effect
useEffect(() => {
console.log(items);
}, [items]);
// ❌ Missing dependency
useEffect(() => {
sendAnalytics(userId);
}, []); // Missing 'userId'
// ✅ Include dependency
useEffect(() => {
sendAnalytics(userId);
}, [userId]);

// ✅ Or use a ref guard inside an effect
const sent = useRef(false);

useEffect(() => {
if (sent.current) {
return;
}

sent.current = true;
sendAnalytics(userId);
}, [userId]);
{
"settings": {
"react-hooks": {
"additionalEffectHooks": "(useMyEffect|useCustomEffect)"
}
}
}
{
"rules": {
"react-hooks/exhaustive-deps": ["warn", {
"additionalHooks": "(useMyCustomHook|useAnotherHook)"
}]
}
}