Navigate
Search topics, hooks, and fundamentals
What if React tore down your Lego creation on every single render?
π§± Theme: Lego Builder
Your component is a Lego workbench. Every render, the builder tears down the previous creation and rebuilds from scratch β even when the instructions haven't changed. useMemo is a display shelf: once you build a tower, you place it on the shelf and only rebuild when the instructions (dependencies) actually change.
Without useMemo, expensive work runs on every render β even when the result would be exactly the same.
Type a name β watch the tower rebuild every keystroke!
useMemo caches the tower and only rebuilds when the instructions (height, color) change. Unrelated changes grab the cached version instantly.
Type a name β the tower stays put! No rebuild needed.
const blocks = useMemo(() => {
return generateBlocks(height, color);
}, [height, color]);
// β Only rebuilds when height or color change!
// Builder name changes? useMemo returns the cached tower.
// No rebuild. Instant.useMemo is like taking a photo of your Lego creation. If nobody changed the pieces, just look at the photo!
useMemo works for any derived data β costs, patterns, statistics. Try these Lego-themed examples.
Bricks
0
Total Cost
$0
Colors Used
0
const stats = useMemo(() => {
const total = bricks.reduce((s, b) => s + b.cost, 0);
const counts = {};
bricks.forEach(b => {
counts[b.name] = (counts[b.name] || 0) + 1;
});
return { total, count: bricks.length, counts };
}, [bricks]); // Only when bricks change
// Toggle "Show Names"? Counter click? Stats stay cached!const grid = useMemo(() => {
return generateGrid(color1, color2, pattern);
}, [color1, color2, pattern]);
// Frame color changes? Grid stays cached!Total
12
Colors
5
Most Common
Red
Rarest
Orange
const stats = useMemo(() => {
const counts = {};
pieces.forEach(p => {
counts[p.name] = (counts[p.name] || 0) + 1;
});
const sorted = Object.entries(counts)
.sort((a, b) => b[1] - a[1]);
return {
total: pieces.length,
uniqueColors: Object.keys(counts).length,
mostCommon: sorted[0]?.[0] ?? "β",
rarest: sorted.at(-1)?.[0] ?? "β",
};
}, [pieces]); // Only when pieces change
// Layout toggle? Stats stay cached!These are the patterns that trip up developers most often. Switch between Wrong and Fixed to compare the code side by side.
function Profile({ firstName, lastName }) {
// useMemo overhead > the concatenation itself
const fullName = useMemo(() => {
return `${firstName} ${lastName}`;
}, [firstName, lastName]);
return <h1>{fullName}</h1>;
}function PriceList({ items }) {
const [discount, setDiscount] = useState(0.1);
const total = useMemo(() => {
return items.reduce((sum, i) => sum + i.price * (1 - discount), 0);
}, [items]); // discount is missing β total uses stale discount
return <div>Total: {total}</div>;
}// Default [] creates a new array every render
function ProductList({ filters = [] }) {
const results = useMemo(() => {
return products.filter(p => applyFilters(p, filters));
}, [filters]); // re-runs EVERY render β new [] each time
return <div>{results.length} products</div>;
}