100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
React

useMemo and useCallback

Learn how useMemo and useCallback memoize values and functions between renders, and when that memoization is actually worthwhile.

Advanced HooksAdvanced12 min readJul 8, 2026
Analogies

Introduction

useMemo and useCallback are both memoization hooks that cache a value across renders and only recompute it when specified dependencies change. useMemo caches the result of a computation, while useCallback caches a function reference itself. Their purpose isn't to make code run faster by default — it's to avoid redoing expensive work or avoid creating new object/function identities unnecessarily, which matters mainly when that recomputation is genuinely costly or when a stable reference is required to prevent a child component from re-rendering or an effect from re-firing.

🏏

Cricket analogy: A team analyst caches Rohit Sharma's strike rate calculation and only reruns it when the overs-faced or runs tally changes, rather than recomputing after every dot ball, saving effort only when the recompute is actually costly.

Syntax

jsx
import { useMemo, useCallback } from 'react';

const sortedList = useMemo(() => {
  return [...items].sort((a, b) => a.price - b.price);
}, [items]);

const handleAddItem = useCallback((item) => {
  setItems((prev) => [...prev, item]);
}, []);

Explanation

useMemo(calculateFn, deps) runs calculateFn during the first render and caches its return value; on subsequent renders it re-runs calculateFn only if one of the values in the deps array has changed since the last render, otherwise it returns the cached result. useCallback(fn, deps) is essentially useMemo specialized for functions: useCallback(fn, deps) is equivalent to useMemo(() => fn, deps) — it returns the same function reference across renders as long as deps haven't changed. It's important to be realistic about the benefit: for cheap computations (simple arithmetic, small array filters, most everyday JSX), the cost of comparing dependency arrays on every render can be roughly the same as, or even more than, just redoing the work, so wrapping everything in useMemo/useCallback by default is a common form of premature optimization that adds cognitive overhead without measurable gain. These hooks earn their keep in two situations: when the computation is genuinely expensive (sorting/filtering large datasets, heavy calculations), or when a stable reference is required — for example, passing a callback to a child wrapped in React.memo so it doesn't re-render on every parent render, or including a function/object in another hook's dependency array without causing it to re-run every time.

🏏

Cricket analogy: Checking whether Rohit's over count changed before recomputing his strike rate is fine for a full innings, but checking it before adding two single runs is slower than just doing the addition — memoizing only pays off for genuinely heavy stats like a full season's economy-rate breakdown.

Example

jsx
const ExpensiveList = React.memo(function ExpensiveList({ items, onSelect }) {
  console.log('ExpensiveList rendered');
  return (
    <ul>
      {items.map((item) => (
        <li key={item.id} onClick={() => onSelect(item.id)}>{item.name}</li>
      ))}
    </ul>
  );
});

function Parent({ items }) {
  const [count, setCount] = useState(0);

  // Stable reference so ExpensiveList doesn't re-render when count changes
  const handleSelect = useCallback((id) => {
    console.log('selected', id);
  }, []);

  const sortedItems = useMemo(
    () => [...items].sort((a, b) => a.name.localeCompare(b.name)),
    [items]
  );

  return (
    <div>
      <button onClick={() => setCount((c) => c + 1)}>Count: {count}</button>
      <ExpensiveList items={sortedItems} onSelect={handleSelect} />
    </div>
  );
}

Output

Clicking the Count button re-renders Parent and updates the displayed count, but because handleSelect and sortedItems keep the same references (their dependencies, [] and items, haven't changed), React.memo sees that ExpensiveList's props are unchanged and skips re-rendering it — 'ExpensiveList rendered' is not logged again. If handleSelect had been recreated as a plain inline function on every render instead, ExpensiveList would re-render on every click even though nothing relevant to it changed, because React.memo's shallow prop comparison would see a new function reference each time.

🏏

Cricket analogy: Even though the scoreboard updates every ball, the pre-recorded team lineup graphic (a stable reference) isn't redrawn because nothing about the lineup changed; if the broadcast regenerated a new lineup graphic object every ball, the display would flicker and redraw needlessly.

Key Takeaways

  • useMemo caches a computed value; useCallback caches a function reference; both only recompute when their dependency array changes.
  • useCallback(fn, deps) behaves like useMemo(() => fn, deps).
  • For cheap computations, memoization can cost as much as or more than just redoing the work — don't apply it by default.
  • Reach for these hooks when a computation is genuinely expensive, or when a stable reference is needed to prevent unnecessary re-renders (often paired with React.memo) or to satisfy another hook's dependency array.
  • An incorrect or incomplete dependency array can cause stale values or bugs, so dependencies must be listed accurately.

Practice what you learned

Was this page helpful?

Topics covered

#React#ReactJsStudyNotes#WebDevelopment#UseMemoAndUseCallback#UseMemo#UseCallback#Syntax#Explanation#StudyNotes#SkillVeris