Hey!
Let me ask you something first.
Every time state changes in React — what happens?
The component re-renders. Every line inside it runs again from top to bottom.
Most of the time — that is fine. But what if one of those lines is doing a heavy calculation? Something that takes real time to compute?
That calculation runs again. Every single render. Even when nothing related to it changed.
That is the problem useMemo fixes.
1. What Is the Problem?
Let us see it in code.
import { useState } from "react";
function App() {
const [count, setCount] = useState(0);
const [input, setInput] = useState("");
function slowCalculation(num) {
console.log("Calculating...");
let result = 0;
for (let i = 0; i < 1000000000; i++) {
result += num;
}
return result;
}
const result = slowCalculation(count);
return (
<div>
<p>Result: {result}</p>
<button onClick={() => setCount(count + 1)}>Increment Count</button>
<input
value={input}
onChange={e => setInput(e.target.value)}
placeholder="Type something..."
/>
</div>
);
}
Quick question for you.
When you type in the input box — does slowCalculation need to run again?
No. The count did not change. The calculation result is still the same.
But React does not know that. It just re-renders everything. So slowCalculation runs again on every keystroke.
Type one letter — calculation runs.
Type another — calculation runs again.
Your app feels slow and unresponsive. All because of an unnecessary recalculation.
That is exactly where useMemo helps.
2. What Is useMemo?
useMemo is a React hook that remembers the result of a calculation.
It only recalculates when the values it depends on actually change.
If nothing it depends on changed — it skips the calculation and returns the saved result from last time.
Think of it like a calculator with memory.
You calculate 2345 * 6789. You press the memory button. Next time someone asks for the same result — the calculator gives it from memory instantly. No recalculating.
useMemo is that memory button for your React components.
3. The Syntax
const result = useMemo(() => {
return someHeavyCalculation(value);
}, [value]);
() => { return ... } — the function that does the calculation.
[value] — the dependency array. useMemo only recalculates when value changes.
If value did not change since last render — useMemo skips the function and returns the saved result.
Looks familiar? Yes — the dependency array works exactly like useEffect.
4. Fixing the Problem With useMemo
Let us fix the slow example from above.
import { useState, useMemo } from "react";
function App() {
const [count, setCount] = useState(0);
const [input, setInput] = useState("");
function slowCalculation(num) {
console.log("Calculating...");
let result = 0;
for (let i = 0; i < 1000000000; i++) {
result += num;
}
return result;
}
const result = useMemo(() => {
return slowCalculation(count);
}, [count]);
return (
<div>
<p>Result: {result}</p>
<button onClick={() => setCount(count + 1)}>Increment Count</button>
<input
value={input}
onChange={e => setInput(e.target.value)}
placeholder="Type something..."
/>
</div>
);
}
Now what happens when you type in the input?
input changes. Component re-renders. But count did not change. So useMemo skips slowCalculation and returns the saved result instantly.
console.log("Calculating...") does not even fire.
Type in the input — smooth. No slowdown.
Click Increment — count changes. Now useMemo recalculates. Because count is in the dependency array.
5. A Simple Real Example — Filtered List
Let us build something more practical.
You have a list of names. A search input filters the list. The filtering runs only when the list or search term changes — not on every render.
import { useState, useMemo } from "react";
const names = ["Ravi", "Anu", "Karthik", "Priya", "Arjun", "Meena", "Vijay"];
function NameList() {
const [search, setSearch] = useState("");
const [count, setCount] = useState(0);
const filteredNames = useMemo(() => {
console.log("Filtering names...");
return names.filter(name =>
name.toLowerCase().includes(search.toLowerCase())
);
}, [search]);
return (
<div>
<input
value={search}
onChange={e => setSearch(e.target.value)}
placeholder="Search names..."
/>
<button onClick={() => setCount(count + 1)}>
Clicked {count} times
</button>
<ul>
{filteredNames.map(name => (
<li key={name}>{name}</li>
))}
</ul>
</div>
);
}
Quick question for you.
When you click the button — does the filter run again?
No. search did not change. useMemo returns the saved filtered list.
When you type in the search box — search changes. Now useMemo runs the filter. Because search is in the dependency array.
The filter only runs when it actually needs to. Not on every button click. Not on every unrelated state change.
6. When Should You Use useMemo?
useMemo is useful — but it is not for everything.
Use it when:
- You have a calculation that is genuinely slow or complex
- The calculation result is used in rendering
- The component re-renders often but the calculation inputs do not always change
Do not use it when:
- The calculation is simple — adding two numbers, filtering a small array of 5 items
- The component rarely re-renders
- You are just trying to "optimise everything" — that is over-engineering
Quick question for you.
Should you wrap 2 + 2 inside useMemo?
No. useMemo itself has a small cost — it needs to store the result and check the dependencies on every render. For something as simple as 2 + 2 — that overhead is more expensive than just calculating it again.
Use useMemo only when the calculation is actually heavy.
7. useMemo vs useEffect — What Is the Difference?
These two both have a dependency array. Beginners sometimes mix them up.
| useMemo | useEffect | |
|---|---|---|
| What it does | Remembers a calculated value | Runs side effects |
| Returns | The calculated value | Nothing |
| When it runs | During render | After render |
| Use for | Expensive calculations | Fetch, timers, subscriptions |
Simple way to remember.
useMemo — "give me a value, but only recalculate when needed."
useEffect — "run this code after something changes."
8. One Common Mistake
Using useMemo for everything — even simple things.
// Overkill — this is too simple to need useMemo
const double = useMemo(() => count * 2, [count]);
// Just do this
const double = count * 2;
useMemo adds overhead. For simple operations — it makes your code slower, not faster.
Only reach for useMemo when you actually feel the slowness. Premature optimisation makes code harder to read for no real gain.
Quick Summary — 4 Things to Remember
React re-renders run every line again — including heavy calculations that did not need to run.
useMemo remembers the result — it only recalculates when the values in the dependency array change.
Use it for genuinely heavy calculations — filtering large lists, complex math, expensive data transformations.
Do not overuse it — simple operations do not need useMemo. The hook itself has a cost. Use it only when you feel the performance problem.
useMemo is one of those hooks you do not need until you need it badly.
When your app starts feeling slow in a specific spot — check if there is a heavy calculation running on every render. Wrap it in useMemo. Watch it become smooth again.
Try the filtered list example above. Add more names. Make the list bigger. Type in the search box and watch the console. Then click the button and see useMemo skip the filter entirely.
That moment when you see it skip — that is when it clicks.
If you have a question — drop it in the comments below.
Thanks for reading. Keep building.
Top comments (0)