useMemo & useCallback
useMemo caches a computed value and recomputes it only when a dependency changes. useCallback caches a function so its reference stays stable across renders. Both are memoization tools: they trade a little memory to skip redundant work. By the end you'll know when each helps — and when it just adds noise.
Learn useMemo & useCallback in our free React course — a beginner-friendly interactive lesson with runnable examples, a practice exercise and a quick recall.
Part of the free React course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
1️⃣ useMemo — Cache a Computed Value
When a component re-renders, every line in its body runs again — including expensive calculations. useMemo remembers the result and recomputes only when a value in its dependency array changes.
The demo models a cache that recomputes only when its input changes — watch the work counter:
Your turn — complete the dependency check so a repeated call reuses the cache:
2️⃣ useCallback — Stable Function References
Every render creates brand-new function objects. Usually that's fine — but if you pass a function to a memoized child, or list it in another hook's dependency array, a fresh reference each render defeats the optimization. useCallback hands back the same function until its deps change.
The demo shows why references matter: a fresh function is never === to another, but a memoized one is:
3️⃣ When NOT to Memoize
Memoization isn't free: React stores the cached value and compares dependencies every render. For cheap computations or functions that aren't passed to memoized children, that overhead can cost more than it saves. Reach for these hooks when you have a measured performance problem, not by reflex.
Rule of thumb: useMemo for expensive values , useCallback for references a child or effect depends on . Everything else: leave it plain.
These lines memoize a filtered list and a stable handler. Put them in a correct, working order:
1) useMemo(() => a + b, [a, b]) — does memoizing this help?
No. Adding two numbers is trivial; the comparison overhead costs more than it saves. Leave it plain.
2) What does useCallback(fn, deps) equal in terms of useMemo?
useMemo(() => fn, deps) . useCallback memoizes the function itself; useMemo memoizes a computed value.
3) A useCallback recreates its function every render. Most likely cause?
A dependency in its array changes every render (often an object/array literal created inline). Stabilize that dependency.
📋 Quick Reference
Use the memoizer to wrap a function. Call it three times with the same input, once with a new input, then log how many times the real work ran. Predict the number before you run it.
Practice quiz
What does useMemo memoize?
- A function itself
- An entire component
- A computed value (the result of running a function)
- A DOM node
Answer: A computed value (the result of running a function). useMemo caches a computed VALUE and only recomputes it when a dependency changes.
What does useCallback memoize?
- The function itself (a stable reference)
- The return value of the function
- The component's props
- The dependency array
Answer: The function itself (a stable reference). useCallback caches the FUNCTION itself so its reference stays stable across renders until its deps change.
useCallback(fn, deps) is equivalent to which useMemo call?
- useMemo(fn, deps)
- useMemo(() => fn(), deps)
- useMemo(fn(), deps)
- useMemo(() => fn, deps)
Answer: useMemo(() => fn, deps). useCallback(fn, deps) === useMemo(() => fn, deps): it returns the function itself rather than calling it.
Why do stable function references matter for a memoized child component?
- Functions run faster when memoized
- A new function reference each render defeats the child's memoization and re-renders it
- React.memo only works with strings
- It prevents the child from mounting
Answer: A new function reference each render defeats the child's memoization and re-renders it. Functions are compared by reference. A fresh function every render is never === to the last one, so a memoized child re-renders anyway unless you give it a stable reference.
Is it worthwhile to write useMemo(() => a + b, [a, b])?
- No — adding two numbers is trivial and the comparison overhead costs more
- Yes, it always speeds things up
- Yes, because addition is expensive
- Only in production
Answer: No — adding two numbers is trivial and the comparison overhead costs more. Memoization has a cost (storing the value, comparing deps). For trivial work like a + b it adds overhead for no benefit.
A useCallback recreates its function on every render. What is the most likely cause?
- React is broken
- The function is too large
- A dependency in its array changes every render (often an inline object/array literal)
- useCallback always recreates
Answer: A dependency in its array changes every render (often an inline object/array literal). If a value in the deps array changes every render (commonly a new object/array literal created inline), the callback is recreated. Stabilize that dependency.
What is the mistake in useMemo(compute(), [a])?
- The deps array is wrong
- compute() is called immediately instead of passing a function
- useMemo needs three arguments
- compute must be async
Answer: compute() is called immediately instead of passing a function. You must pass a function: useMemo(() => compute(), [a]). Writing compute() runs it immediately every render, defeating memoization.
Do useMemo and useCallback prevent re-renders by themselves?
- Yes, they stop all re-renders
- Yes, but only for class components
- No, they have no effect on rendering
- No — they give stable references; React.memo on the child uses them to skip its render
Answer: No — they give stable references; React.memo on the child uses them to skip its render. These hooks provide stable references/values. React.memo on the child uses those stable references to skip its own re-render — they work together.
Which is a good use case for useMemo?
- Adding two numbers
- Sorting or filtering thousands of rows
- Reading a constant string
- Logging to the console
Answer: Sorting or filtering thousands of rows. useMemo is worth it for genuinely expensive computations like sorting/filtering large arrays, not trivial operations.
What is wrong with useMemo(fn, []) when fn reads a prop value?
- Nothing, it is ideal
- It recomputes too often
- It never refreshes, so it keeps a stale value when the prop changes
- Empty arrays are not allowed
Answer: It never refreshes, so it keeps a stale value when the prop changes. An empty deps array never changes, so the cached value never refreshes even when the value it reads changes. Include every value the computation reads.