When do (and don’t) children re-render in React?
Photo by Ferenc Almasi on Unsplash
When writing React components, we always strive to keep optimization in mind. It’s always useful to know when unnecessary re-rendering occurs in our code, especially if we have heavy components in our app.
So let’s dive in and see what happens with child components when their parents re-render.
In most cases we use child components by their name. Let’s examine the following code:
import { useState } from "react";
const Parent = () => {
const [number, setNumber] = useState(0);
console.log('<Parent> renders');
return (
<div>
Number is {number}
<div>
<button onClick={() => setNumber(prev => prev + 1)}>
Increment
</button>
</div>
<Child />
</div>
);
};
const Child = () => {
/* Some time-consuming logic... */
console.log('<Child> renders');
return (
<div>
<div>Child component</div>
</div>
);
};
const App = () => {
return (
<Parent />
);
};
export default App;
Every time the button is pressed, the state of the Parent
component changes and it re-renders, which causes re-rendering <Child />
component as well.
How can we prevent unnecessary re-renders for the Child
component? Let’s explore two approaches to achieve this
Approach 1: Our friend React.memo
If we wrap the Child component into React.memo, the Parent’s re-render will not cause the Child to re-render.
Quick reminder — React.memo
memoizes components, ensuring they are not re-rendered when their props remain unchanged.
import { memo, useState } from "react";
const Parent = () => {
const [number, setNumber] = useState(0);
console.log('<Parent> renders');
return (
<div>
Number is {number}
<div>
<button onClick={() => setNumber(prev => prev + 1)}>
Increment
</button>
</div>
<Child />
</div>
);
};
const Child = memo(() => {
/* Some time-consuming logic... */
console.log('<Child> renders');
return (
<div>
<div>Child component</div>
</div>
);
});
const App = () => {
return (
<Parent />
);
};
export default App;
This is, in fact, one of the ways to stop unnecessary re-renders.
Approach 2: Using {children}
prop
We can use children prop to achieve the same result. Let’s see it in action.
{children}
prop allows the parent component to accept and render its children components dynamically.
import {useState} from "react";
const Parent = ({children}) => {
const [number, setNumber] = useState(0);
console.log('<Parent> renders');
return (<div>
Number is {number}
<div>
<button onClick={() => setNumber(prev => prev + 1)}>
Increment
</button>
</div>
{children}
</div>);
};
const Child = () => {
// Some time-consuming logic
console.log('<Child> renders');
return (
<div>
<div>Child component</div>
</div>
);
};
const App = () => {
return (
<Parent>
<Child />
</Parent>
);
};
export default App;
Using children
prop here makes the code easier to follow, and also removes extra clutter coming from memo
.
While these 2 approaches help us remove unnecessary re-rendering child components, bear in mind that we don’t need to blindly optimize everything. If our component doesn’t involve heavy calculations or other performance bottlenecks, we usually shouldn’t prematurely optimize it. Always strive to keep components small and easy to follow, and optimize them only when necessary.
Thanks for reading! If you have any notes, remarks or questions, please share them in the comments.
Stay updated with the latest JavaScript and software development news! Join my Telegram channel for more insights and discussions: TechSavvy: Frontend & Backend.
Subscribe to my newsletter
Read articles from Vardan Hakobyan directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Vardan Hakobyan
Vardan Hakobyan
Hi, I'm a seasoned software engineer with a strong focus on JavaScript. I'm passionate about sharing my knowledge and experiences to help others learn something new and avoid the same pitfalls I've encountered along the way.