The useMemo hook in React is a powerful tool for optimizing performance by memoizing expensive computations. By using useMemo, you can avoid unnecessary recalculations, especially in large and complex applications where performance is critical. This chapter explores the useMemo hook in depth, from basic usage to advanced techniques, with practical examples to demonstrate its benefits.
The useMemo hook returns a memoized value, which is recomputed only when one of its dependencies changes. It helps to optimize performance by skipping expensive calculations if the inputs (dependencies) haven’t changed.
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
Let’s start with a simple example to understand the basic usage of useMemo.
import React, { useState, useMemo } from 'react';
function App() {
const [count, setCount] = useState(0);
const [text, setText] = useState('');
const expensiveCalculation = (num) => {
console.log('Calculating...');
for (let i = 0; i < 1000000000; i++) {} // Simulate expensive calculation
return num * 2;
};
const memoizedValue = useMemo(() => expensiveCalculation(count), [count]);
return (
useMemo Example
Count: {count}
Expensive Calculation Result: {memoizedValue}
setText(e.target.value)}
placeholder="Type something"
/>
);
}
export default App;
count and text.expensiveCalculation function simulates a CPU-intensive task.useMemo memoizes the result of expensiveCalculation(count) and recalculates it only when count changes.memoizedValue is displayed alongside the count and a text input.When you run this application, you’ll see the count and the result of the expensive calculation. The console will log “Calculating…” only when the count changes, not when the text input is updated.
In this example, we will use useMemo to efficiently filter a large list of items based on user input.
import React, { useState, useMemo } from 'react';
const items = Array.from({ length: 10000 }, (_, i) => `Item ${i + 1}`);
function App() {
const [search, setSearch] = useState('');
const filteredItems = useMemo(() => {
console.log('Filtering items...');
return items.filter((item) =>
item.toLowerCase().includes(search.toLowerCase())
);
}, [search]);
return (
useMemo Filtering Example
setSearch(e.target.value)}
placeholder="Search items"
/>
{filteredItems.map((item, index) => (
- {item}
))}
);
}
export default App;
items) with 10,000 elements.filteredItems array is computed using useMemo and recalculated only when search changes.search state is updated via an input field, and the filtered items are displayed in a list.When you run this application, you’ll see a search input and a list of items. The console will log “Filtering items…” only when the search input changes, demonstrating efficient filtering of the large data set.
In this example, we will memoize a component that performs an expensive render operation to optimize performance.
import React, { useState, useMemo } from 'react';
function ExpensiveComponent({ count }) {
console.log('Rendering ExpensiveComponent...');
for (let i = 0; i < 1000000000; i++) {} // Simulate expensive render
return Expensive Component Count: {count}
;
}
function App() {
const [count, setCount] = useState(0);
const [text, setText] = useState('');
const memoizedComponent = useMemo(() => {
return ;
}, [count]);
return (
useMemo Component Example
{memoizedComponent}
setText(e.target.value)}
placeholder="Type something"
/>
);
}
export default App;
ExpensiveComponent simulates an expensive render operation.useMemo memoizes the ExpensiveComponent and re-renders it only when count changes.When you run this application, you’ll see the count and the expensive component. The console will log “Rendering ExpensiveComponent…” only when the count changes, not when the text input is updated, demonstrating optimized rendering.
useMemo can also be used to memoize callbacks, though useCallback is more commonly used for this purpose. However, let’s see how useMemo can achieve the same.
import React, { useState, useMemo } from 'react';
function Child({ onClick }) {
console.log('Rendering Child...');
return ;
}
function App() {
const [count, setCount] = useState(0);
const [text, setText] = useState('');
const memoizedCallback = useMemo(() => {
return () => {
setCount((prevCount) => prevCount + 1);
};
}, []);
return (
useMemo Callback Example
Count: {count}
setText(e.target.value)}
placeholder="Type something"
/>
);
}
export default App;
memoizedCallback is memoized using useMemo and recalculated only once because it has an empty dependency array.Child component uses the memoized callback.Child component is re-rendered only when memoizedCallback changes.When you run this application, you’ll see a button and a count. The console will log “Rendering Child…” only once, demonstrating the memoized callback’s effectiveness.
In this example, we will use useMemo to memoize the result of a computation-heavy function. This will help us avoid re-computation when the input data hasn’t changed.
import React, { useState, useMemo } from 'react';
function App() {
const [count, setCount] = useState(0);
const [otherCount, setOtherCount] = useState(0);
const expensiveCalculation = (num) => {
console.log('Performing expensive calculation...');
for (let i = 0; i < 1000000000; i++) {} // Simulate expensive calculation
return num * 2;
};
const memoizedValue = useMemo(() => expensiveCalculation(count), [count]);
return (
useMemo Example: Expensive Calculation
Count: {count}
Other Count: {otherCount}
Expensive Calculation Result: {memoizedValue}
);
}
export default App;
count and otherCount.expensiveCalculation function simulates a CPU-intensive task.useMemo memoizes the result of expensiveCalculation(count) and recalculates it only when count changes.memoizedValue is displayed alongside the count and other count values.When you run this application, you’ll see the counts and the result of the expensive calculation. The console will log “Performing expensive calculation…” only when the count changes, not when the other count is updated.
In this example, we will use useMemo to efficiently filter a large list of items based on user input. This can help to optimize performance when working with large data sets.
import React, { useState, useMemo } from 'react';
const items = Array.from({ length: 10000 }, (_, i) => `Item ${i + 1}`);
function App() {
const [search, setSearch] = useState('');
const filteredItems = useMemo(() => {
console.log('Filtering items...');
return items.filter((item) =>
item.toLowerCase().includes(search.toLowerCase())
);
}, [search]);
return (
useMemo Example: Filtering Large List
setSearch(e.target.value)}
placeholder="Search items"
/>
{filteredItems.map((item, index) => (
- {item}
))}
);
}
export default App;
items) with 10,000 elements.filteredItems array is computed using useMemo and recalculated only when search changes.search state is updated via an input field, and the filtered items are displayed in a list.When you run this application, you’ll see a search input and a list of items. The console will log “Filtering items…” only when the search input changes, demonstrating efficient filtering of the large data set.

The useMemo hook in React is essential for optimizing performance by memoizing expensive computations and preventing unnecessary recalculations. By understanding and effectively using useMemo, you can enhance the efficiency of your React applications, especially in scenarios involving large data sets, complex calculations, and expensive renders. Happy coding !❤️
