
Part 1: React Rendering Demystified — What Actually Causes Re-Renders?
July 14, 2025
Ashish Gogula

July 14, 2025
Ashish Gogula
Before optimizing React performance, you need to understand the “why” behind re-renders. This post is a deep dive into React’s rendering behavior, what triggers it, and how to control it like a pro.
In simple terms, a re-render happens when React re-executes your component function to figure out what the updated UI should look like. This doesn’t always mean something changes in the actual DOM, but React still goes through the process of running the component and generating a new version of the UI.
During each re-render:
Here’s a simplified version of what happens when React renders a component:
This cycle repeats as your app interacts with the user or data updates.
There are four main things that can trigger a re-render:
This last point is especially important. Child components are not automatically optimized to skip re-renders unless you explicitly handle it.
Prop drilling means passing data down through multiple levels of components — even if only the component at the bottom actually needs it.
Here’s an example:
<Parent>
<Middle>
<Child />
</Middle>
</Parent>
If the Parent has state that changes and is passed all the way down to Child, then every component in the chain (Parent, Middle, and Child) will re-render when that state updates.
In small apps, this usually isn’t noticeable. But in larger apps, especially when deep trees or expensive components are involved, this can slow things down.
Reconciliation is how React compares the old and new versions of your UI and updates only what’s different.
React doesn’t update the real DOM directly every time something changes. Instead, it uses a virtual DOM — a lightweight, in-memory representation of the UI.
On every re-render:
This makes React very efficient — but the component still has to re-run to generate the virtual DOM. So even if no DOM updates are made, unnecessary renders still add overhead.
Let’s take a simple example:
function Parent() {
const [count, setCount] = useState(0);
return (
<>
<button onClick={() => setCount(count + 1)}>Increment</button>
<Child />
</>
);
}
function Child() {
console.log('Child rendered');
return <p>I’m a child component</p>;
}
Every time you click the button, Parent re-renders because its state changes. That causes Child to re-render too — even though it doesn’t use the count state at all.
This is the default behavior in React. Unless you prevent it using tools like React.memo, children will always re-render when their parent does.
To observe this yourself, open the browser console and interact with the button. You’ll see "Child rendered" logged every time.
Here’s what to take away from this post:
In Part 2, I’ll go over how to reduce these unnecessary renders using memoization, pure components, and other practical techniques you can apply in any project.
