The react-hooks/exhaustive-deps rule warns when values used inside useMemo aren't listed in the dependency array, which causes the memoized result to become stale as props or state change.
React raises this warning via the react-hooks/exhaustive-deps ESLint rule whenever the callback passed to useMemo references props, state, context, or helper values that are missing from the dependency array. useMemo only recalculates when one of the dependencies changes, so omitting a value causes React to keep returning the previously cached result even after the dependency has updated. In other words, you get a stale memoized value that no longer reflects the current render. The rule enforces complete dependency tracking so every reactive value that influences the calculation is declared, which keeps your memoized values in sync with your component's latest state.
Check the ESLint warning to identify which variable is missing, then add it to the dependency array. React will rerun the memoized calculation whenever that dependency changes, keeping the result fresh:
const visibleTodos = useMemo(() => {
return filterTodos(todos, tab);
}, [todos, tab]); // now tab and todos are trackedObjects and arrays created directly inside the component body get a new reference on every render, so they defeat dependency tracking. Wrap them in useMemo or move them inside the hook:
const searchOptions = useMemo(() => ({ matchMode: 'whole-word', query }), [query]);
const visibleItems = useMemo(() => {
return searchItems(items, searchOptions);
}, [items, searchOptions]);This keeps searchOptions stable whenever query stays the same.
If useMemo depends on a helper function or derived value that captures props or state, wrap that helper in useMemo/useCallback so it has a stable identity and can be tracked safely:
const createFormatter = useCallback((locale) => {
return new Intl.ListFormat(locale, { style: 'long' });
}, []);
const formatted = useMemo(() => {
const formatter = createFormatter(locale);
return formatter.format(items);
}, [items, locale, createFormatter]);If a value never changes, define it at module scope so it does not need to appear in the dependency array:
const API_ENDPOINT = 'https://api.example.com/batch';
function Dashboard() {
const response = useMemo(() => fetchData(API_ENDPOINT), []);
// no missing dependency warning because API_ENDPOINT never changes
}When you deliberately want to reuse the same memoized value even though another value changes, hold that value in a ref and read ref.current inside useMemo. Refs do not belong in dependency arrays:
const intervalRef = useRef(interval);
useEffect(() => {
intervalRef.current = interval;
}, [interval]);
const timer = useMemo(() => {
return createTimer(intervalRef.current);
}, []);This keeps the timer stable while still reading the latest interval.
Add an eslint-disable-next-line comment only when you have a documented reason for skipping the dependency:
const loadOnce = useMemo(() => {
fetchSnapshot(snapshotId);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []); // intentionally ignoring snapshotId because it should run onceWarnings exist because missing dependencies usually cause bugs. Only skip them when you fully understand the consequences.
useMemo is purely an optimization helper, so keep the calculation pure and make sure all dependencies are stable. React still runs the memoized function at least once per render in development (Strict Mode double-invokes it) to detect side effects, so omitting dependencies hides real bugs. The react-hooks/exhaustive-deps rule compares dependencies with Object.is, so any unstable object/array reference needs its own memoization or rearrangement. If you find yourself memoizing functions, useCallback is usually clearer. Debug missing dependencies by logging the dependency array and comparing values with Object.is between renders. Keeping the dependency array honest avoids stale memoized results and keeps memoized child components rerendering when their inputs actually change.
React Hook useCallback has a missing dependency: 'variable'. Either include it or remove the dependency array react-hooks/exhaustive-deps
React Hook useCallback has a missing dependency
Cannot use private fields in class components without TS support
Cannot use private fields in class components without TS support
Cannot destructure property 'xxx' of 'undefined'
Cannot destructure property of undefined when accessing props
useNavigate() may be used only in the context of a <Router> component.
useNavigate() may be used only in the context of a Router component
Cannot find module or its corresponding type declarations
How to fix "Cannot find module or type declarations" in Vite