React re-renders can slow down your app, especially with expensive calculations. The useMemo
hook helps optimize performance by memoizing values, ensuring that unnecessary computations are avoided.
In this post, you’ll learn about the useMemo
hook, including its syntax and how it works with examples.
Before we get started, don’t forget to subscribe to my newsletter!
Get the latest tips, tools, and resources to level up your web development skills delivered straight to your inbox. Subscribe here!
Now, let’s jump right into it!
What is useMemo?
useMemo
is a React Hook used to optimize expensive calculations. This memoizes the computed values to avoid calculation on every render.
This is useful for improving performance, especially with large lists, heavy computations, or unnecessary renders.
For example, imagine you have a large list that needs filtering every time a user types in a search box. Without optimization, performance slows down as filtering runs on every render. useMemo helps solve this problem by caching the filtered results.
If an expensive calculation is happening repeatedly without any state change, then you can optimize this using useMemo
.
Basic Syntax of useMemo
Before using useMemo
, you need to import it from React:
import { useMemo } from "react";
Syntax:
const memoizedValue = useMemo(() => computeExpensiveValue(dependencies), [dependencies]);
Here,
-
useMemo
accepts a function that performs expensive calculations. -
useMemo
caches the result of the expensive function. - This will recalculate only when dependencies change.
- If dependencies don’t change, then it will return the memoized value without computation.
Without useMemo (Unoptimized Code)
If you do expensive calculations on each render, then React will do unnecessary re-calculations, which is not good for performance.
For example:
import { useState } from "react";
function ExpensiveComponent({ numbers }) {
function sum(numbers) {
console.log("Calculating sum...");
return numbers.reduce((acc, num) => acc + num, 0);
}
const [count, setCount] = useState(0);
const total = sum(numbers); // This will calculate on every render
return (
<div>
<p>Sum: {total}</p>
<button onClick={() => setCount(count + 1)}>Re-render: {count}</button>
</div>
);
}
export default function App() {
return <ExpensiveComponent numbers={[1, 2, 3, 4, 5]} />;
}
How does it work?
- The
useState
hook is imported to manage state inside the component. - The
ExpensiveComponent
function takes a numbers prop, which is an array of numbers. - Inside the component, a function
sum( )
calculates the sum of the numbers using thereduce()
method and logs “Calculating sum…” to track how often it runs. - A state variable
count
is initialized with 0, and thesetCount
function updates it when the button is clicked. - The issue arises because the
sum( )
function is called on every render, even when the numbers prop hasn’t changed, leading to unnecessary recalculations. - The component displays the sum and a button that increments the count, triggering a re-render.
- The App component renders
ExpensiveComponent
with a predefined list of numbers.
Problem with This Code:
Every time the button is clicked, setCount
updates the state. React re-renders the component, and the sum( )
is called again, even though the numbers didn’t change. This is inefficient, especially for complex calculations.
Solution:
Using the useMemo
hook can optimize this by memoizing the computed sum, ensuring it only recalculates when the numbers prop changes. This prevents unnecessary executions and improves performance.
With useMemo (Optimized Code)
You can use useMemo
in the above example to avoid unnecessary calculations.
import { useState, useMemo } from "react";
function ExpensiveComponent({ numbers }) {
function sum(numbers) {
console.log("Calculating sum...");
return numbers.reduce((acc, num) => acc + num, 0);
}
const [count, setCount] = useState(0);
const total = useMemo(() => sum(numbers), [numbers]); // Recalculates only when `numbers` change
return (
<div>
<p>Sum: {total}</p>
<button onClick={() => setCount(count + 1)}>Re-render: {count}</button>
</div>
);
}
export default function App() {
return <ExpensiveComponent numbers={[1, 2, 3, 4, 5]} />;
}
How does it work?
- The
useState
anduseMemo
hooks are imported from React. - The
ExpensiveComponent
function receives a numbers prop, which is an array. - Inside the component, the
sum( )
function calculates the sum of the numbers and logs “Calculating sum…” to track executions. - A state variable
count
is initialized with 0, andsetCount
updates it when the button is clicked. - The
useMemo
hook is used to memoize the result of thesum(numbers)
. This ensures the sum is only recalculated when numbers change, preventing unnecessary computations on re-renders. - The component displays the sum and a button that increments the count, triggering a re-render.
- The App component renders
ExpensiveComponent
with a predefined list of numbers.
Why is this better?
Without useMemo
, sum( )
runs on every re-render, even if the numbers stay the same. With useMemo
, sum( )
runs only when numbers change, improving performance.
useMemo in Large List Filtering
You can optimize the sorting or filtering of a large list using the useMemo
hook.
Without useMemo (Unoptimized List Filtering)
import { useState } from "react";
function List({ items, filterText }) {
const filteredItems = items.filter(item => item.includes(filterText)); // Filtering will happen on every render
return (
<ul>
{filteredItems.map(item => (
<li key={item}>{item}</li>
))}
</ul>
);
}
export default function App() {
const [filterText, setFilterText] = useState("");
return (
<div>
<input onChange={(e) => setFilterText(e.target.value)} />
<List items={["apple", "banana", "grape", "orange", "pineapple"]} filterText={filterText} />
</div>
);
}
What does this code do?
- It renders a list of fruits (items) and filters them based on the text entered in the input field (filterText).
- Whenever the user types in the input, the list updates dynamically to show only the matching items.
How does it work?
State Management (useState):
-
filterText
is a state variable initialized as an empty string (""). -
setFilterText
updatesfilterText
whenever the user types in the input field.
Filtering Logic (Inside List Component):
- The
filteredItems
array is created usingitems.filter(item => item.includes(filterText))
. - This means if
filterText = “ap”
, it will return[“apple”, “grape”, “pineapple”]
.
Rendering the List (map()
):
-
filteredItems.map(item => <li key={item}>{item}</li>)
maps each filtered item into a<li>
inside<ul>
.
Re-rendering Issue:
- Every time
filterText
changes, the App component re-renders, causing List to re-runfilter()
. - This is inefficient for large lists.
With useMemo (Optimized List Filtering)
import { useState, useMemo } from "react";
function List({ items, filterText }) {
const filteredItems = useMemo(() => {
console.log("Filtering list...");
return items.filter(item => item.includes(filterText));
}, [items, filterText]); // Filter only when `items` or `filterText` changes
return (
<ul>
{filteredItems.map(item => (
<li key={item}>{item}</li>
))}
</ul>
);
}
export default function App() {
const [filterText, setFilterText] = useState("");
return (
<div>
<input onChange={(e) => setFilterText(e.target.value)} />
<List items={["apple", "banana", "grape", "orange", "pineapple"]} filterText={filterText} />
</div>
);
}
What does this code do?
- It filters a list of fruits (items) based on user input (filterText).
- Uses
useMemo
to optimize filtering and prevent unnecessary recalculations.
How does it work?
State Management (useState
):
-
filterText
is stored usinguseState
. - When the user types in the input field,
setFilterText
updates the state.
Filtering Optimization (useMemo
):
-
filteredItems
is memoized usinguseMemo()
, ensuring filtering happens only when items orfilterText
changes. - Without
useMemo
, filtering would run on every render, even iffilterText
stays the same.
Console Logging for Debugging:
- “Filtering list…” logs when filtering runs.
- If the input remains unchanged, filtering won’t run, proving memoization works.
Rendering the List (map()
):
- The
filteredItems
array is mapped into<li>
elements inside<ul>
.
Why is this better than the previous version?
Without useMemo
, filtering runs on every render. With useMemo
, it runs only when necessary, improving performance, especially for large lists.
What is the difference between useCallback and useMemo?
Feature | useCallback | useMemo |
---|---|---|
Purpose | Function memoization | Value memoization |
Returns | Memoized function reference | Memoized computed value |
Use Case | When unnecessary function recreation happening | When expensive calculation is happening repeatedly |
In simple:
- If you need to memoize a function, use
useCallback
. - If you need to memoize a computed value or expensive calculation, use
useMemo
.
🎯Wrapping Up
That’s all for today!
For paid collaboration connect with me at : connect@shefali.dev
I hope this post helps you.
If you found this post helpful, here’s how you can support my work:
☕ Buy me a coffee – Every little contribution keeps me motivated!
📩 Subscribe to my newsletter – Get the latest tech tips, tools & resources.
𝕏 Follow me on X (Twitter) – I share daily web development tips & insights.
Keep coding & happy learning!
Top comments (0)