Understanding useEffect and React.memo in React


What is useEffect
?
useEffect
is a React hook used for handling side effects (code that interacts with the outside world or modifies things outside React’s rendering, e.g., API calls, timers, DOM updates).It runs after React has finished rendering the component.
Why does it run at the end?
Here’s an implementation of useEffect
:
function App() {
let[color, setColor] = useState('black');
console.log('render');
useEffect(()=>{
console.log('Render useEffect');
document.body.style.backgroundColor = color;
}, [color]);
console.log('Last Line Executed');
return (
<div>
<button onClick={()=>{setColor('red')}}>Red</button>
<button onClick={()=>{setColor('green')}}>Green</button>
<button onClick={()=>{setColor('blue')}}>Blue</button>
<button onClick={()=>{setColor('pink')}}>Pink</button>
<button onClick={()=>{setColor('orange')}}>Orange</button>
</div>
);
}
In this code:
console.log('render');
useEffect(() => {
console.log('Render useEffect');
document.body.style.backgroundColor = color;
}, [color]);
console.log('Last Line Executed');
console.log('render')
→ Runs during the rendering phase.console.log('Last Line Executed')
→ Runs after all synchronous code in the component finishes.Then React calls
useEffect
→ because effects run after the render phase (non-blocking).
👉 This ensures the UI is updated first, then side effects (like DOM manipulation) are applied.
render
Last Line Executed
Render useEffect
Dependencies ([color]
)
The dependency array controls when the effect runs:
[]
→ Runs only once (on mount).[color]
→ Runs every timecolor
changes.No array → Runs after every render (bad for performance).
Why do DOM manipulations go inside useEffect
?
React's render updates the Virtual DOM first.
If you manipulate the real DOM inside the render function, it can conflict with React’s updates.
useEffect
runs after rendering, so DOM is stable, and manipulations won't break React’s rendering cycle.
What is React.memo
?
React.memo
is a higher-order component (HOC) used to optimize functional components.It prevents unnecessary re-renders when a component’s props haven't changed.
Works similarly to
PureComponent
for class components.
How does it work?
When a parent component re-renders:
Normally, all its child components also re-render, even if their props remain the same.
Wrapping a component in
React.memo()
makes React compare the previous and new props:If props are the same → React skips re-rendering the child.
If props changed → Child re-renders.
Example
// Parent component
function App() {
let [count, setCount] = useState(0);
return (
<div>
<div>
<h1>Count: {count}</h1>
<button onClick={() => setCount(count + 1)}>Increment</button>
<button onClick={() => setCount(count - 1)}>Decrement</button>
</div>
<Colorful />
</div>
);
}
// Child component
function Colorful () {
let[color, setColor] = useState('black');
console.log('render');
useEffect(()=>{
console.log('Render useEffect');
document.body.style.backgroundColor = color;
}, [color]);
console.log('Last Line Executed');
return (
<div>
<button onClick={()=>{setColor('red')}}>Red</button>
<button onClick={()=>{setColor('green')}}>Green</button>
<button onClick={()=>{setColor('blue')}}>Blue</button>
<button onClick={()=>{setColor('pink')}}>Pink</button>
<button onClick={()=>{setColor('orange')}}>Orange</button>
</div>
);
}
export default React.memo(Colorful);
The
App
component re-renders every timecount
changes.Without
React.memo
, theColorful
component would also re-render each time even though it does not depend oncount
(its state is independent).
Colorful
Component with React.memo
export default React.memo(Colorful);
Now, React checks if
Colorful
received any new props fromApp
:Colorful
doesn't receive any props.Therefore, its props never change → React skips re-rendering when
App
updates.
The
Colorful
component will only re-render when:Its own state changes (
color
changes).It receives new props (not applicable here).
function App() {
const [count, setCount] = useState(0);
return (
<div>
<div>
<h1>Count: {count}</h1>
<button onClick={() => setCount(count + 1)}>Increment</button>
<button onClick={() => setCount(count - 1)}>Decrement</button>
</div>
{/* Pass count as props */}
<Colorful count={count} />
</div>
);
}
function Colorful({ count }) {
const [color, setColor] = useState('black');
console.log('render');
useEffect(() => {
console.log('Render useEffect');
document.body.style.backgroundColor = color;
}, [color]);
console.log('Last Line Executed');
return (
<div>
<h2>Received Count: {count}</h2>
<button onClick={() => setColor('red')}>Red</button>
<button onClick={() => setColor('green')}>Green</button>
<button onClick={() => setColor('blue')}>Blue</button>
<button onClick={() => setColor('pink')}>Pink</button>
<button onClick={() => setColor('orange')}>Orange</button>
</div>
);
}
export default React.memo(Colorful);
How React.memo
works now
Each time
count
changes in the parent (App
),App
re-renders.React.memo checks if the props of
Colorful
have changed:The
count
prop does change (new number each time you increment/decrement).Therefore, React will re-render
Colorful
.
If you click a color button,
Colorful
re-renders because its own state changes (this happens regardless ofReact.memo
).
When will Colorful
skip re-render?
If the same props are passed:
<Colorful count={5} />
and the next render also passes
count={5}
, React.memo will skip the re-render.But when
count
actually changes (e.g., 1 → 2), React.memo cannot skip because props are different.
Why is this important?
It avoids unnecessary rendering of
Colorful
whencount
changes in the parent.This improves performance, especially for components with heavy rendering or complex calculations.
Summary
useEffect
: Runs after render for side effects (DOM updates, API calls). Runs when dependencies change.React.memo
: Skips re-rendering a child if props are unchanged, improving performance.
Subscribe to my newsletter
Read articles from Hridoy Chowdhury directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Hridoy Chowdhury
Hridoy Chowdhury
I'm a Computer Science & Engineering student exploring the world of Blockchain, Web Development (MERN), and coding interview prep. I write to reinforce my learning and share insights that make complex ideas simpler. Always building, always learning.