Reacting and re-rendering are as connected as a rocket is to gravity. Without understanding gravity, rocket science is... well, you get the point. The same is true with React and its first principle, re-rendering.
Why we don't use let or const
When you examine what is happening in the above code (just keep an eye on the output for now and play with the white buttons), you will understand that
The value of the "stateless" variable
a
(variables declared with let or const) is getting updated in the console, but the UI is not in sync with the latest or current value of the variablea
.The opposite is the case with the state variable
b
. Every time there is a change in the value of the variableb
, the UI is automatically updated, or we can say the UI is in sync with the latest value of the state variableb
.
But the obvious question here is why the same is not happening with the stateless variable a. Why do we use state for a component in React? Why don't or can't we use const or let, as they are variables too, right?
React's main job is to keep the UI in sync with the latest value of the state of the respective component. How, then, is React going to do that? Well, the answer is re-rendering. I know we are getting ahead of ourselves. So, let's take a look at the typical counter example.
What causes a re-render?
When a component is first displayed on the screen, i.e., when the UI is first rendered, we call it the "initial render." Now the UI will be displayed according to the initial state value of the component. When a component is initially rendered, React creates a tree of components that represent the UI (DOM). The Dom tree at the time when the component is first displayed on the screen would be like this: ๐
initial render
<div>
<h1>
1
</h1>
<button>
increase +
</button>
</div>
When we click on the yellow button, the value of the count variable flips from 0 to 1, i.e., it increases by one. So each time there is a change in the state of a component (in our case, count), React again constructs the DOM tree. Why? Because then, how would React keep the UI in sync with the latest value of the state of the component? It has to look for changes being made after there was a change in the state of the component by comparing the two DOM trees.
But React is designed or created in such a way that whenever any state of a component changes, React updates the virtual representation of the HTML DOM first and then compares it with the previous virtual DOM. React then updates only the necessary parts of the actual webpage (not the whole page) based on the changes that occurred in the virtual DOM. This process is called reconciliation.
Reconciliation is simply React comparing the previous virtual DOM tree with the new one and calculating the minimum number of changes needed to update the actual DOM. This process of reconciliation is triggered when any state of the component is updated. We don't need to go deep into the concepts of virtual DOM and reconciliation; just keep in mind that React with each render does not construct a new DOM tree but has effective ways to make things work rather than constructing the entire DOM tree again through the virtual DOM.
Spot the differences game
Think of it like this: Each render is a snapshot or an image that React captures, and it plays the "spot the differences game" with each render. It compares the two snapshots, in our case the virtual DOMs, and updates the component with the latest necessary changes, i.e., the value of the state.
And for this comparison to happen, we need a trigger. Let and const don't trigger a re-render. Every re-render is caused by a state change. For a component to re-render, the only trigger is a change in any state associated with that component. So re-render is simply React updating the component with the latest value of the state variable.
The child does not affect the parent.
Now, a re-render is limited to the component that owns that state, i.e., where the state is declared. A change in the state of a child does not cause an application-wide re-render and also does not cause the parent to re-render.
In the illustration below, whenever there is any change in the state of the components Child1, App (parent), and Child2 (sibling), they won't go through the process of re-rendering. Re-renders only affect the component that owns the state and its descendants (children). React is like a surgeon who precisely operates on only the affected area without causing unnecessary harm to the surrounding healthy tissue. This surgical approach makes React efficient and fast.
Parent affects all the children (descendants).
But whenever the parent re-renders, all its descendants (children) re-render too, whether they're being passed a particular state variable through props or not. But that should not be the case, right? Why make the children go through the process of re-rendering if their state has not changed?
Well, the thing is, when a parent component updates in React, all of its child components are marked as needing to be updated because their rendering or behavior may be impacted by changes in the parent component through props. React then checks each child component to see if its data (props or state) has changed. If the data hasn't changed, React reuses the existing snapshot and updates its data as necessary, rather than creating a new snapshot from scratch.
So saying that all children re-render when a parent updates is kind of wrong because not all children go through the process of re-rendering. They are checked first to see if they need to re-render or not. But this checking process happens when the parent re-renders. Therefore, it is more accurate to say that when the parent component re-renders, all of its descendants (children) are checked for updates, and those that need to be updated are re-rendered.
Let's see re-rendering in action.
Download the extension called React Developer Tools https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi?hl=en
- After installing it on your Chrome browser, just click on inspect and open the devtools with
Ctrl
+Alt
+I
(orโ
+Option
+I
on MacOS).
In the profile section, click on the settings icon.
After enabling "Highlight updates when components render," you'll notice little green boxes popping up around components that re-render. (DevTools should be opened to see the boxes.)
Lastly, I feel that, as developers, we tend to overestimate the impact of state variables on React's rendering system and worry about the performance issues of using state. While overusing state can certainly impact performance, it's crucial to remember that React's rendering system is a well-oiled machine, only updating what's necessary and optimizing performance with built-in tools. So, don't shy away from using state when you need it; just use it wisely and trust React's rendering magic to do the rest!