Memoizing Values
Memoizing Values
useMemo returns a memoized value that only changes when dependencies change.
Basic Usage
import { useMemo } from "react";
function ExpensiveComponent({ data }) {
const processedData = useMemo(() => {
// Expensive computation
return data.map((item) => ({
...item,
computed: heavyCalculation(item)
}));
}, [data]); // Only re-computes when data changes
return (
<ul>
{processedData.map((item) => (
<li key={item.id}>{item.computed}</li>
))}
</ul>
);
}
Without useMemo
// Bad: Re-computes on every render
function Component({ items, filter }) {
const filteredItems = items.filter((item) => item.category === filter);
// filteredItems is a new array every render
}
With useMemo
// Good: Only re-computes when items or filter change
function Component({ items, filter }) {
const filteredItems = useMemo(
() => items.filter((item) => item.category === filter),
[items, filter]
);
}
Comparing Results
function SortedList({ items, sortKey }) {
const sortedItems = useMemo(() => {
return [...items].sort((a, b) => {
if (a[sortKey] < b[sortKey]) return -1;
if (a[sortKey] > b[sortKey]) return 1;
return 0;
});
}, [items, sortKey]);
return (
<ul>
{sortedItems.map((item) => (
<li key={item.id}>{item.name}</li>
))}
</ul>
);
}
When to Use
When to Use
Good Use Cases
- Expensive computations
const result = useMemo(() => {
return performComplexCalculation(data);
}, [data]);
- Filtering/sorting large lists
const filteredItems = useMemo(
() => items.filter((item) => item.active),
[items]
);
- Referential equality for props
const options = useMemo(() => ({
sort: sortBy,
filter: filterBy
}), [sortBy, filterBy]);
// Pass to child that checks object equality
<ChildComponent options={options} />
When NOT to Use
- Simple computations (overhead > benefit)
- When dependencies change frequently
- For primitive values (already memoized)
Cost vs Benefit
// Don't useMemo for this
const doubled = useMemo(() => count * 2, [count]);
// Just use: const doubled = count * 2;
// Do useMemo for this
const expensiveResult = useMemo(() => {
return data.reduce((acc, item) => {
return acc + complexCalculation(item);
}, 0);
}, [data]);
Measuring Performance
function Component({ items }) {
const start = performance.now();
const result = useMemo(() => {
return items.map(complexTransform);
}, [items]);
const end = performance.now();
console.log(`Computed in ${end - start}ms`);
}
Performance Impact
Performance Impact
How useMemo Helps
- Avoids re-computing expensive operations
- Maintains referential equality for objects/arrays
- Prevents unnecessary child re-renders
With React.memo
const ChildComponent = React.memo(({ items }) => {
// Only re-renders if items prop changes (reference equality)
return (
<ul>
{items.map((item) => (
<li key={item.id}>{item.name}</li>
))}
</ul>
);
});
function Parent({ filter }) {
const items = getItems();
// Without useMemo: new array every render = Child always re-renders
const filteredItems = items.filter((i) => i.category === filter);
// With useMemo: same array reference = Child doesn't re-render
const filteredItems = useMemo(
() => items.filter((i) => i.category === filter),
[items, filter]
);
return <ChildComponent items={filteredItems} />;
}
Common Pitfalls
// Bad: Empty deps but uses external variable
const result = useMemo(() => compute(value), []); // Missing value!
// Bad: Creating new object in deps
const options = useMemo(() => ({ sort }), [sort]); // OK
// But: <Child options={options} /> // options is new reference each time
// Fix: ensure Child uses memo or callbacks
// Good: Include all dependencies
const result = useMemo(() => compute(a, b), [a, b]);
Performance Checklist
- Expensive computation (>10ms)
- Large data transformations
- Need referential equality
- Passing to memoized children
- Dependencies don't change often
Practice Problems
Create a reusable React component implementing useMemo. Include proper state management and accessibility.
Solution
// Production-ready component with:
// - Proper TypeScript types
// - Accessibility (ARIA)
// - Error boundaries
// - Loading states
// - Memoization where neededWrite unit and integration tests for useMemo using React Testing Library.
Solution
// Test coverage:
// 1. Rendering tests
// 2. Interaction tests
// 3. Edge case tests
// 4. Accessibility testsOptimize useMemo for performance. Consider memoization, code splitting, and bundle size.
Solution
// Optimization techniques:
// 1. React.memo / useMemo / useCallback
// 2. Code splitting with lazy()
// 3. Virtual scrolling for lists
// 4. Image lazy loading
// 5. Bundle analysisQuiz
1. What does useMemo return?
2. When should you use useMemo?
3. What is the benefit of useMemo?
4. When should you NOT use useMemo?
Flashcards
Question
What does useMemo do?
Click to reveal answer
Answer
Memoizes a value so it only recalculates when dependencies change
Question
When should you use useMemo?
Click to reveal answer
Answer
For expensive computations with stable dependencies
Question
What is referential equality?
Click to reveal answer
Answer
Two variables pointing to the same object in memory
Question
When should you NOT use useMemo?
Click to reveal answer
Answer
For simple computations where the overhead exceeds the benefit
Question
What is useMemo?
Click to reveal answer
Answer
useMemo is a key concept in frontend development.
Revision Notes
Key Takeaways
- 1.useMemo memoizes expensive computations
- 2.Only re-computes when dependencies change
- 3.Useful for referential equality
- 4.Don't use for simple computations
- 5.Helps prevent unnecessary child re-renders
Interview Tips
- •Explain when useMemo is beneficial
- •Show how it works with React.memo
- •Discuss the cost vs benefit tradeoff
Cheat Sheet
Cheat Sheet
Basic Usage
const result = useMemo(() => {
return expensiveCalc(data);
}, [data]);
When to Use
- Expensive computations
- Filtering/sorting large lists
- Need referential equality
- Passing to memoized children
Don't Use For
- Simple computations
- Primitive values
- Dependencies that change often
With React.memo
const Child = React.memo(({ items }) => ...);
const items = useMemo(() => filter(data), [data]);
<Child items={items} /> // Won't re-render if items unchanged