Note useMemo caches the result of a computation. React may discard the cache under memory pressure, so never rely on it for correctness -- only for performance. Do not memoize everything by default; profile first.
Note useCallback(fn, deps) is identical to useMemo(() => fn, deps). Its primary use case is passing stable function references to memoized child components (wrapped with React.memo) to prevent their re-renders.
Note Missing a dependency leads to stale closures. Including an unnecessary one causes pointless recalculations. Use the exhaustive-deps lint rule (eslint-plugin-react-hooks) to catch mistakes automatically.
Note React.memo does a shallow comparison of props. It only helps if the component re-renders with the same props frequently. Pair it with useCallback for function props and useMemo for object/array props.
// DO memoize when:// - Computation is genuinely expensive (sorting large arrays, complex math)// - Passing callbacks/objects to React.memo children// - Value is a dependency of another hook// DON'T memoize when:// - The computation is trivial// - The component rarely re-renders// - No downstream consumer cares about reference stability
Note Memoization has a cost: it uses memory to store results and adds comparison overhead. Only apply it where profiling shows a measurable benefit. Premature memoization adds complexity without improving performance.
when to memoizeperformance optimizationshould I useMemomemoization decisionoptimize or not
function DataFetcher({ endpoint, filters }) {
// Without useMemo, a new object is created every render,// causing the effect to re-run endlesslyconst requestConfig = useMemo(
() => ({
url: endpoint,
params: filters,
headers: { 'Accept': 'application/json' },
}),
[endpoint, filters]
);
useEffect(() => {
const controller = new AbortController();
fetch(requestConfig.url, {
...requestConfig,
signal: controller.signal,
}).then(r => r.json()).then(setData);
return () => controller.abort();
}, [requestConfig]);
}
Note When an object or array is a dependency of useEffect, memoize it to prevent infinite effect loops. Every render creates a new reference, and useEffect sees a 'change' even when the values inside are identical.
stable referencereferential equalityprevent infinite loopobject dependencymemoize for effect