When do (and don’t) children re-render in React?
Vardan Hakobyan
Posted on September 19, 2024
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;
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 two 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.
Posted on September 19, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.