Topic 46 of 54
Caching Math
Overview
Sometimes a component is slow not because of the DOM, but because it's doing heavy JavaScript math (like sorting an array of 50,000 items or parsing a massive string). If the component re-renders for an unrelated reason (like a text input changing), that heavy math runs again! `useMemo` caches (memoizes) the *result* of a calculation, only recalculating it if its dependencies change.
Syntax
Without `useMemo`, clicking the 'Toggle Theme' button would trigger the 100,000-item filter and sort all over again, causing noticeable UI lag.
Caching an Expensive Calculation
jsx
import { useState, useMemo } from 'react';
function DataVisualizer({ users }) {
const [theme, setTheme] = useState("light"); // Unrelated state
// 1. Pass a function that returns the calculated value
// 2. Pass a dependency array
const activeUsers = useMemo(() => {
console.log("Filtering 100,000 users...");
return users.filter(u => u.isActive && u.score > 50).sort();
}, [users]); // ONLY recalculate if the 'users' prop actually changes
return (
<div className={theme}>
<button onClick={() => setTheme(t => t === 'light' ? 'dark' : 'light')}>
Toggle Theme
</button>
<p>Found {activeUsers.length} active users</p>
</div>
);
}Common Pitfalls
- Using `useMemo` for trivial calculations like `x + y` or `array.map(id => id)`. The overhead of `useMemo` itself is often slower than just doing the simple math.
- Writing side effects (like API calls) inside `useMemo`. It must be a pure function that only returns data.
Interview Tips
- Don't confuse `React.memo` (which caches a whole *Component*) with `useMemo` (which caches a specific *Value/Variable* inside a component).
Real-World Example
Using `useMemo` to keep an Object Reference stable so that `React.memo` on a child component doesn't break.
example
jsx
function Parent({ name }) {
// If we just did: const config = { color: 'red' };
// It would be a new object in memory every render.
// This guarantees the object reference stays identical across renders.
const config = useMemo(() => ({ color: 'red' }), []);
return <MemoizedChild config={config} />;
}