Why React renders?

A dive deep into how and why react renders to understand and avoid unnecessary renders in react

We know that whenever there is a state change in React, it will result in a re-render. Recently, I came across a beautiful way to describe React in terms of the function of the state, which can be written as v=f(s), this means the view will only change when the state changes.

But how exactly does React know that the state has changed?

via GIPHY

To understand that, let's first define what is Rendering?

Rendering means that React will call our component with the intention of updating the view.

Whenever rendering takes place in React, two things happen:

  1. React takes a snapshot of the component which captures all the information React needs to update the view, state, props, event handlers and a description of the UI(based on state & props).

  2. React updates the view based on the description of the UI in the snapshot.

To get the initial UI description, React does an initial render starting at the root of the application, this is done using the below code, which all of us have seen in the index.js file of create-react-app or wrote it ourselves in case building react app from scratch.

const rootElement = document.getElementById("root");
const root = React.createRoot(rootElement);
root.render(<App/>);

So, after the initial render, whenever a state changes React will perform a re-render and to figure out state has changed, React makes use of the snapshot it took before. Whenever a useState() is invoked, React will check if the new state is different than the previous state by using something called a diffing algorithm and if the state has changed it will perform a re-render and take a new snapshot and replace it with the previous one.

Let's look at some React code and figure out how and why will react re-render in these examples

import * as React from "react"
function UpdateName() {
  const [name, setName] = React.useState("John")
  const handleClick = () => {
    setName("Joey");
  }
  return (
    <main>
      <h1>Hello, {name}</h1>
      <button onClick={handleClick}>Next</button>
    </main>
  )
}
export default function App () {
  return <UpdateName/>
}

In the example below, React will perform an initial render and capture all the details in a snapshot.

  1. What happens after we click on Next?

    • As soon as setName() is invoked, React will compare the previous state captured in the initial snapshot with the new incoming state and since they are different, React will capture the new snapshot with the new state and replace the old snapshot, and a re-render will take place.

    • Now here comes the trick part, What happens when we click the button again?

      So as per our understanding so far, it seems like React will perform a re-render as a state change is invoked. right?

      Well sorry to disappoint you, but that's not the case. In fact, React is smart enough to know that even though we invoke a state change we are not changing our state value, so React will smartly ignore this and will not perform any re-render.

      Impressive isn't it?

      via GIPHY

import * as React from "react"
function UpdateName() {
  const [theme, setTheme] = React.useState("light")
  const handleClick = () => {
    setTheme("dark");
    alert(theme)
  }
  return (
    <main>
      <h1>Current theme is:{theme}</h1>
      <button onClick={handleClick}>Change theme</button>
    </main>
  )
}
export default function App () {
  return <UpdateName/>
}

What do you think we get in alert here when we click on the change theme button?

Remember how we talked about React comparing the two snapshots, well since React has access to the previous snapshot inside the event handler and it will only update the snapshot after the re-render, what do you think the value of theme is inside the function?

If you thought, "light" then my friend you are correct. Pat yourself on your back!!

Now, what happens after the second click?

Well, that's straightforward, we will have "dark" in the alert, right?

Let's see what happens for the clicks after that. Again, quite a simple answer, it will be "dark" for all the other clicks as we are not changing our state after that.

import * as React from "react";
function UpdateName() {
  const [count, setCount] = React.useState(0);
  const handleClick = () => {
    setCount(count+1);
    setCount(count+1);
    setCount(count+1);
  };
  console.log("rendering...");
  return (
    <main>
      <h1>Count is:{count}</h1>
      <button onClick={handleClick}>+</button>
    </main>
  );
}
export default function App() {
  return <UpdateName />;
}

Hmmm, what's going on here? Let's try to answer how many times will React re-render on every function invocation here.

Your intuition might be 3 re-renders on every click, right?

Well, not quite true, because if this was how React handled re-renders we might have run into a lot of performance issues due to re-renders.

Thankfully, React is efficient enough to not let us worry about it. React uses something called batching in this case.

Batching means that React will take into account every state change in an event handler before performing a re-render.

So that means our app will only re-render once per click here.

Phew!! Thanks to React for saving us from this hell of re-renders.

Okay, let's tackle a last tricky part related to state change.

What do you think will be the value of count in this event handler?

  const handleClick = () => {
    setCount(1);
    setCount(c=>c+2);
    setCount(5);
    setCount(c=>c+10)
  };

Looks complicated?

Well, not that complicated though. What happens is, in the first setCount(1), we tell React to forget whatever value count had and set it to 1 instead. But, in setCount(c=>c+2), we are telling React, to take the previous value of count and increment it by 2 and set the result as the new value of count, which is 3.

I guess now you might be able to answer it correctly!

Yepp, you are right, the final value of count will be 15 by applying the same rule as we did above.

That's it for now folks! Now, whenever you feel it's a re-render that's causing the performance issues, maybe think again, because as we saw React handles re-renders pretty well so we should not worry about it much.

I hope this has helped you understand React in a better way and you enjoyed reading this! If so, please like and share it with fellow React devs to help them

Also, don't forget to leave your valuable comments in case you have any feedback or questions.

Also, if you want to learn more about these kind of concepts, I would encourage you to check out this beautiful course on![React](https://react.gg/).

Thank you for reading!!

Did you find this article valuable?

Support Sakshi Chaudhary by becoming a sponsor. Any amount is appreciated!