← Back to Chapters

React useMemo() Hook

⚛️ React useMemo() Hook

⚡ Memoize expensive calculations   ? Recompute only when needed

? Quick Overview

The React useMemo() Hook memoizes the result of a computation — it caches a calculated value and only recomputes it when one of its dependencies changes.

This is useful when you have expensive calculations (loops, filters, derived data, heavy transformations) that you don’t want to run on every render.

Think of useMemo as telling React: “Only recompute this value if something important changes.”

? Key Concepts

  • Memoization: Caching the result of a function so it doesn’t need to run again unnecessarily.
  • Dependencies: The array of values that control when the memoized value should be recalculated.
  • Expensive computations: Operations like big loops, filters, sorting, or heavy formulas.
  • Derived data: Values computed from state/props (e.g., filtered lists, totals, statistics).
  • Performance optimization: Use useMemo only when there is a measurable benefit.

? Syntax

Basic syntax for useMemo():

? View Code Example
// Memoize an expensive computation based on dependencies a and b
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
  • First argument — a function that returns the computed value.
  • Second argument — a dependency array; React recomputes the value when any dependency changes.
  • If dependencies do not change between renders, React reuses the cached value.

? Example 1: Basic Expensive Calculation

Imagine a component that performs a very heavy calculation inside a large loop. Without useMemo, this calculation would re-run on every render.

? View Code Example
// Component that memoizes a very expensive calculation
function ExpensiveCalculation({ number }) {
const expensiveValue = React.useMemo(() => {
console.log("Calculating...");
let total = 0;
for (let i = 0; i < 100000000; i++) {
total += number * 2;
}
return total;
}, [number]);

return (
<div>
<h4>Calculated Value: {expensiveValue}</h4>
</div>
);
}

? Explanation

  • The heavy loop runs inside the useMemo callback.
  • The value expensiveValue is cached until number changes.
  • Re-renders that don’t change number will reuse the existing result, improving performance.

? Example 2: Filtering / Derived State

useMemo is great for computing derived state, like filtered lists based on user input.

? View Code Example
// Filter a list of users efficiently using useMemo
function FilterList() {
const [query, setQuery] = React.useState("");
const users = ["Alice", "Bob", "Charlie", "David", "Eve"];

const filtered = React.useMemo(() => {
console.log("Filtering...");
return users.filter((u) => u.toLowerCase().includes(query.toLowerCase()));
}, [query]);

return (
<div>
<input
placeholder="Search..."
value={query}
onChange={(e) => setQuery(e.target.value)}
/>
<ul>
{filtered.map((user) => (
<li key={user}>{user}</li>
))}
</ul>
</div>
);
}

? Explanation

  • The filtered list is derived from users and the search query.
  • The filtering runs only when query changes.
  • Other re-renders reuse the memoized filtered list, avoiding repeated filter work.

? Example 3: useMemo + React.memo Child Component

Combine useMemo with React.memo to prevent unnecessary re-renders of child components.

? View Code Example
// Parent & child components optimized with useMemo and React.memo
const UserList = React.memo(({ users }) => {
console.log("UserList rendered");
return (
<ul>
{users.map((u) => (
<li key={u}>{u}</li>
))}
</ul>
);
});

function App() {
const [filter, setFilter] = React.useState("");
const [count, setCount] = React.useState(0);
const users = ["Anna", "Brian", "Chris", "Diana"];

const filteredUsers = React.useMemo(() => {
return users.filter((u) => u.toLowerCase().includes(filter.toLowerCase()));
}, [filter]);

return (
<div>
<input
placeholder="Filter users..."
value={filter}
onChange={(e) => setFilter(e.target.value)}
/>

<UserList users={filteredUsers} />

<button onClick={() => setCount(count + 1)}>
Increment ({count})
</button>
</div>
);
}

? Explanation

  • UserList is wrapped with React.memo, so it only re-renders when its users prop changes.
  • filteredUsers is memoized using useMemo, based on the filter value.
  • Changing count does not cause UserList to re-render, improving efficiency.

? useMemo() vs useCallback()

Both use a dependency array, but they memoize different things:

Aspect useMemo() useCallback()
Purpose Memoizes a computed value Memoizes a function
Returns Cached value Stable callback reference
Common Use Expensive calculations, derived data Event handlers, callbacks passed to children
Recomputed When Dependencies change Dependencies change

⚠️ Performance Notes & Pitfalls

  • ? Avoid using useMemo everywhere — it itself has a small overhead.
  • ? Don’t forget dependencies in the array; missing values can lead to stale or incorrect results.
  • ? Don’t wrap random values directly — always provide a function that returns the computed value.
  • ✅ Use it primarily when you have measurably expensive logic or a noticeable performance issue.

? Tips & Best Practices

  • Use useMemo for expensive logic (loops, filters, heavy calculations) — not for simple variables.
  • Great for optimizing derived state that depends on other state/props.
  • Combine useMemo with React.memo or useCallback to limit child re-renders.
  • Always profile your app before optimizing — unnecessary memoization can make code harder to read.
  • Keep dependency arrays accurate and explicit to avoid bugs.

? Try It Yourself

  1. Build a component that calculates the factorial or Fibonacci of a number. Use useMemo to memoize the computed result.
  2. Create a page with a large list of items and implement search / filter / sort using useMemo so that the list is recomputed only when needed.
  3. Wrap a child list component with React.memo, pass it a memoized value from useMemo, and verify that it does not re-render when unrelated state changes.
  4. Temporarily remove useMemo from your examples and compare how many times computations and child components run using console.log().

Goal: Understand how useMemo() improves performance by memoizing computational results so that React recalculates values only when dependencies change, not on every render.