Welcome back to “Let’s Master React Hooks Together” — the series where we learn React hooks step by step in the most beginner-friendly way possible.
So far in this series, we’ve already explored hooks like useState and useEffect, and by now you’ve probably started noticing one important thing about React:
React components re-render a lot.
And honestly, that’s completely normal. React is designed that way.
But once applications start growing, re-rendering can sometimes create performance problems — especially when expensive calculations run again and again unnecessarily.
That’s exactly where today’s hook enters the picture:
useMemo()
At first glance, useMemo looks confusing. Many beginners memorize the syntax without actually understanding:
- what problem it solves,
- why it exists,
- and how it connects with
useEffect.
So in this 8th episode, we’re going to slow things down and understand useMemo properly from the ground up.
We’ll learn:
- the official definition,
- beginner-friendly explanation,
- how memoization works,
- how dependency arrays behave,
- how
useEffectconnects withuseMemo, - why
useEffectdoes not return values, - and how
useMemoactually returns optimized values.
And just like the previous episodes in this series, we’ll not only write code — we’ll also break down the execution flow step by step so you can understand what React is actually doing behind the scenes.
So let’s dive in and finally make useMemo feel simple.
Official Definition of useMemo
According to the React documentation:
useMemois a React Hook that lets you cache the result of a calculation between re-renders.
This is the official explanation. But honestly, for beginners, this sentence alone is not very easy to understand.
So let’s simplify it.
Beginner Friendly Definition of useMemo
In simple words:
useMemoremembers a calculated value so React doesn’t calculate it again and again during every re-render.
Or even simpler:
useMemohelps React avoid unnecessary work.
That is the core idea.
React components re-render frequently. During those renders, calculations also run again. If some calculation is expensive, repeatedly running it can slow down the application. useMemo helps optimize that.
Before Learning useMemo, Understand Re-Rendering
To properly understand useMemo, you first need to understand one very important concept in React:
React re-renders components very often.
Whenever:
- state changes,
- props change,
- or parent components re-render,
React runs the component function again.
Look at this example:
import { useState } from "react";
function App() {
const [count, setCount] = useState(0);
console.log("Component Rendered");
return (
<div>
<h1>{count}</h1>
<button onClick={() => setCount(count + 1)}>
Increase
</button>
</div>
);
}
export default App;
At first, this code looks very small and harmless. But internally, React is doing more than beginners realize.
Step-by-Step Flow of the Code
When the component loads for the first time, React starts executing:
function App()
Inside the component, React creates state using:
const [count, setCount] = useState(0);
Now:
-
countbecomes0 -
setCountbecomes the function that updates state
After that, this line runs:
console.log("Component Rendered");
Then React returns the JSX and displays the UI.
When the button is clicked:
setCount(count + 1)
React updates the state.
And this is the important part:
React re-renders the entire component again.
That means:
- the component function runs again,
- variables recreate,
- functions recreate,
- calculations rerun,
- console logs rerun.
This behavior is exactly why hooks like useMemo exist.
Why useMemo Exists
Most of the time, re-rendering is completely fine. React is fast.
But imagine your component contains:
- huge filtering logic,
- expensive calculations,
- sorting large arrays,
- heavy data processing.
Now every re-render becomes expensive.
Even unrelated state changes can trigger those calculations again.
That creates unnecessary work.
To solve this optimization problem, React introduced:
useMemo()
Its job is simple:
- remember old calculated results,
- and reuse them if dependencies did not change.
Official Syntax of useMemo
const memoizedValue = useMemo(() => {
return expensiveCalculation();
}, [dependencies]);
At first glance, this syntax may look scary. But it becomes simple once we break it down carefully.
Understanding the Syntax Step by Step
The first part is the function:
() => {
return expensiveCalculation();
}
This contains the calculation React should remember.
And notice something important here:
return expensiveCalculation();
useMemo RETURNS a value.
This is one of the biggest differences between useMemo and useEffect.
Then comes the dependency array:
[dependencies]
This tells React:
“Only rerun this calculation if these values change.”
This dependency system is exactly why beginners often connect useMemo with useEffect.
Because useEffect also uses dependency arrays.
Official Definition of useEffect
According to React:
useEffectlets you synchronize a component with external systems.
That sounds complicated too.
So let’s simplify it.
Beginner Friendly Definition of useEffect
In simple words:
useEffectruns some code after rendering.
Usually developers use it for:
- API calls,
- timers,
- localStorage,
- subscriptions,
- DOM updates.
So while useMemo focuses on remembering values, useEffect focuses on running actions.
Very Important Difference
useEffect Does NOT Return Values
This is one of the most important beginner understandings.
Look at this:
const value = useMemo(() => {
return 10;
}, []);
Here:
useMemo
returns a value.
That returned value gets stored inside:
value
Now compare it with:
useEffect(() => {
console.log("Hello");
}, []);
This does NOT return a UI value.
useEffect simply runs some code after rendering.
So:
| Hook | Returns Value? |
|---|---|
useMemo |
Yes |
useEffect |
No |
This is a very important connectivity proof between both hooks.
One stores values.
The other performs actions.
Important Connection Between useMemo and useEffect
This is where many beginners get confused.
Both hooks use dependency arrays.
Example:
useEffect(() => {
console.log("Effect running");
}, [count]);
and
useMemo(() => {
return count * 2;
}, [count]);
Both are watching:
[count]
Whenever count changes:
-
useEffectreruns, -
useMemorecalculates.
That’s why they feel similar.
But internally, their purpose is different.
Difference Between useMemo and useEffect
The easiest way to understand them is this:
| Hook | Purpose |
|---|---|
useMemo |
Remember calculated values |
useEffect |
Run side effects/actions |
You can also remember it like this:
useMemo
“Remember this value.”
useEffect
“Run this action.”
This one-line understanding helps a lot.
Example Without useMemo
Now let’s see the real problem.
import { useState } from "react";
function App() {
const [count, setCount] = useState(0);
const [dark, setDark] = useState(false);
function slowFunction(num) {
console.log("Heavy Calculation Running...");
for (let i = 0; i < 1000000000; i++) {}
return num * 2;
}
const doubledNumber = slowFunction(count);
return (
<div>
<h1>{doubledNumber}</h1>
<button onClick={() => setCount(count + 1)}>
Increase
</button>
<button onClick={() => setDark(!dark)}>
Toggle Theme
</button>
</div>
);
}
At first, this code may look fine. But there’s an important issue hidden inside it.
What Happens Internally Here?
When the component renders:
-
slowFunction(count)runs, - heavy calculation happens,
- React displays the result.
Now suppose the user clicks:
Toggle Theme
This updates:
dark
state.
Even though:
-
countdid not change, - the heavy calculation still runs again.
Why?
Because React re-rendered the component, and everything inside the component executed again.
That is unnecessary work.
This is exactly where useMemo helps.
Fixing It with useMemo
import { useMemo, useState } from "react";
function App() {
const [count, setCount] = useState(0);
const [dark, setDark] = useState(false);
function slowFunction(num) {
console.log("Heavy Calculation Running...");
for (let i = 0; i < 1000000000; i++) {}
return num * 2;
}
const doubledNumber = useMemo(() => {
return slowFunction(count);
}, [count]);
return (
<div>
<h1>{doubledNumber}</h1>
<button onClick={() => setCount(count + 1)}>
Increase
</button>
<button onClick={() => setDark(!dark)}>
Toggle Theme
</button>
</div>
);
}
Now the behavior changes.
Flow of This Code
When the component renders for the first time:
-
useMemoruns, -
slowFunction(count)executes, - React stores the result,
- React also stores the dependency:
[count]
Now suppose theme changes.
React re-renders the component again.
But before recalculating, React compares old dependencies with new dependencies.
If:
count
did not change,
React skips the expensive calculation and reuses the old stored value.
This is called:
memoization
And that’s where the name useMemo comes from.
Combining useMemo with useEffect
Now let’s connect both hooks together.
import { useEffect, useMemo, useState } from "react";
function App() {
const [number, setNumber] = useState(1);
const squared = useMemo(() => {
console.log("Calculating...");
return number * number;
}, [number]);
useEffect(() => {
console.log("Squared value changed:", squared);
}, [squared]);
return (
<div>
<h1>{squared}</h1>
<button onClick={() => setNumber(number + 1)}>
Increase
</button>
</div>
);
}
This example is the best proof of connectivity between:
useMemo- and
useEffect
Now get in to this flow
When the component loads:
-
numberstate initializes, -
useMemocalculates:
number * number
- React stores the returned value inside:
squared
This proves:
useMemo
returns a value.
Now React renders the UI.
After rendering finishes:
useEffect
runs.
Notice:
-
useEffectdid not create a value, - it only performed an action:
console.log()
This proves:
useEffect
does NOT return UI values.
Now suppose the button is clicked.
setNumber(number + 1)
updates state.
React re-renders again.
Then:
-
useMemochecks[number] - dependency changed,
- calculation reruns,
- new squared value gets returned.
Now:
useEffect
detects that:
[squared]
changed.
So the effect runs again.
This is the real relationship:
-
useMemocreates optimized returned values -
useEffectreacts when those values change
Once beginners understand this execution flow, both hooks become much easier.
Common Beginner Mistakes
One of the biggest beginner mistakes is using useMemo everywhere.
Example:
const value = useMemo(() => {
return count + 1;
}, [count]);
This is unnecessary because:
count + 1
is already extremely fast.
useMemo itself also has a small cost.
So optimization should only happen when calculations are actually expensive.
Another common mistake is incorrect dependencies:
useMemo(() => {
return count * 2;
}, []);
Now the value never updates because dependencies are empty.
The same dependency problems also happen in useEffect.
So dependency arrays are very important in both hooks.
Final Thoughts
For beginners, useMemo feels confusing because it introduces optimization concepts early.
But the core idea is actually simple.
React components re-render often. During those renders, calculations also rerun. If those calculations are expensive, useMemo helps React remember previous results and avoid unnecessary work.
At the same time:
-
useMemoreturns optimized values, - while
useEffectperforms actions after rendering.
So together:
-
useMemostores optimized calculated values, -
useEffectreacts when values change.
And that’s a wrap for Episode 8 of “Let’s Master React Hooks Together.”
If useMemo felt confusing before, hopefully now it feels much more practical and less scary.
In the next episodes, we’ll continue exploring more React hooks, deeper concepts, and real-world React patterns step by step in the same beginner-friendly style.
Until then:
- experiment with these examples,
- change dependencies,
- observe re-renders,
- and keep building projects.
Because the more you practice React hooks, the more natural they become.
See you in Episode 9 of “Let’s Master React Hooks Together.”
Top comments (0)