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,
-
useMemoaccepts a function that performs expensive calculations. -
useMemocaches 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
useStatehook is imported to manage state inside the component. - The
ExpensiveComponentfunction 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
countis initialized with 0, and thesetCountfunction 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
ExpensiveComponentwith 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
useStateanduseMemohooks are imported from React. - The
ExpensiveComponentfunction 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
countis initialized with 0, andsetCountupdates it when the button is clicked. - The
useMemohook 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
ExpensiveComponentwith 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):
-
filterTextis a state variable initialized as an empty string (""). -
setFilterTextupdatesfilterTextwhenever the user types in the input field.
Filtering Logic (Inside List Component):
- The
filteredItemsarray 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
filterTextchanges, 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
useMemoto optimize filtering and prevent unnecessary recalculations.
How does it work?
State Management (useState):
-
filterTextis stored usinguseState. - When the user types in the input field,
setFilterTextupdates the state.
Filtering Optimization (useMemo):
-
filteredItemsis memoized usinguseMemo(), ensuring filtering happens only when items orfilterTextchanges. - Without
useMemo, filtering would run on every render, even iffilterTextstays 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
filteredItemsarray 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!
By the way, if you ever need free HTML website templates, I recommend checking out HTMLrev, I use it all the time. And when I’m looking for web design inspiration, Websitevice is one of my go-to resources.
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)