React useMemo
Optimizing expensive calculations in React
💾 What is useMemo?
useMemo is a React Hook that memoizes computed values. It caches the result of expensive calculations and only recalculates when dependencies change, improving performance.
import { useMemo } from 'react';
function MyComponent({ items }) {
const total = useMemo(() => {
return items.reduce((sum, item) => sum + item.price, 0);
}, [items]);
return <p>Total: ${total}</p>;
}
useMemo Concepts
Memoization
Caches computed values between renders
const value = useMemo(() => compute(), deps);
Expensive Calculations
Optimizes heavy computations
const result = useMemo(() => heavyCalc(data), [data]);
Dependencies
Recalculates when deps change
useMemo(fn, [dep1, dep2]);
Return Value
Returns the memoized result
const memoizedValue = useMemo(...);
🔹 Basic useMemo Example
useMemo prevents recalculating expensive operations on every render. This example shows filtering a large list only when the filter or list changes.
import { useState, useMemo } from 'react';
function ProductList({ products }) {
const [filter, setFilter] = useState('');
// Only recalculates when products or filter changes
const filteredProducts = useMemo(() => {
console.log('Filtering products...');
return products.filter(product =>
product.name.toLowerCase().includes(filter.toLowerCase())
);
}, [products, filter]);
return (
<div>
<input
value={filter}
onChange={(e) => setFilter(e.target.value)}
placeholder="Search products..."
/>
<p>Found {filteredProducts.length} products</p>
<ul>
{filteredProducts.map(product => (
<li key={product.id}>{product.name} - ${product.price}</li>
))}
</ul>
</div>
);
}
Output:
Found 3 products
- Laptop - $999
- Mouse - $29
- Keyboard - $79
🔹 Expensive Calculation Example
useMemo shines with computationally expensive operations. This factorial calculator only recalculates when the number changes, not on every render.
import { useState, useMemo } from 'react';
function FactorialCalculator() {
const [number, setNumber] = useState(5);
const [theme, setTheme] = useState('light');
// Expensive calculation - only runs when number changes
const factorial = useMemo(() => {
console.log('Calculating factorial...');
let result = 1;
for (let i = 1; i <= number; i++) {
result *= i;
}
return result;
}, [number]);
return (
<div className={theme}>
<input
type="number"
value={number}
onChange={(e) => setNumber(Number(e.target.value))}
min="0"
max="20"
/>
<p>Factorial of {number} is: {factorial}</p>
<button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>
Toggle Theme
</button>
<p>Factorial doesn't recalculate when theme changes!</p>
</div>
);
}
Output:
Factorial of 5 is: 120
Factorial doesn't recalculate when theme changes!
🔹 useMemo with Object/Array
useMemo is useful for creating stable object or array references. This prevents unnecessary re-renders in child components that depend on these values.
import { useState, useMemo } from 'react';
function UserProfile({ userId }) {
const [theme, setTheme] = useState('light');
// Object reference stays the same if userId doesn't change
const userConfig = useMemo(() => {
return {
id: userId,
settings: {
theme: 'auto',
notifications: true
}
};
}, [userId]);
// Array reference stays the same
const permissions = useMemo(() => {
return ['read', 'write', 'delete'];
}, []); // Empty deps - never changes
return (
<div>
<p>User ID: {userConfig.id}</p>
<p>Permissions: {permissions.join(', ')}</p>
<button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>
Toggle Theme
</button>
</div>
);
}
🔹 When to Use useMemo
useMemo should be used strategically for performance optimization:
✅ Use useMemo when:
- Expensive calculations: Complex computations, sorting, filtering large arrays
- Referential equality matters: Value passed to memoized child components
- Derived state: Computing values from props or state
- Performance issues: Measurable slowdown without memoization
❌ Don't use useMemo when:
- Simple calculations: Basic math, string operations
- Premature optimization: No performance problem exists
- Every value: Adds unnecessary complexity
- Primitive values: Numbers, strings, booleans (unless expensive to compute)
🔹 useMemo vs useCallback
Both hooks memoize values, but they serve different purposes:
import { useMemo, useCallback } from 'react';
function Comparison() {
// useMemo - memoizes the RESULT of a function
const expensiveValue = useMemo(() => {
return computeExpensiveValue();
}, [dependency]);
// useCallback - memoizes the FUNCTION itself
const memoizedCallback = useCallback(() => {
doSomething();
}, [dependency]);
// Equivalent to:
const memoizedCallback2 = useMemo(() => {
return () => doSomething();
}, [dependency]);
return <div>{expensiveValue}</div>;
}
- useMemo: Returns a memoized VALUE
- useCallback: Returns a memoized FUNCTION
- useCallback(fn, deps): Same as useMemo(() => fn, deps)