Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

React extra execution on set state

I am trying to understand the React hook set state cycle. With this example:

let counter = 0;

export const Example = () => {
    const [state, setState] = React.useState({ isActive: false });

    console.log(`render`);
    counter++;

    return (
        <div>
            <div
                style={{ border: `1px solid ${state.isActive ? 'red' : 'black'}` }}
                onMouseDown={() => setState(prevState => (prevState.isActive ? prevState : { isActive: true }))}
            >
                Text caption
            </div>
            Render - {counter}x
        </div>
    );
};

If I click on Text caption multiple times, the HTML will end up with Render - 2x. But there will be 3 console logs. When I click on it the first time, the state is changed. But for the second time I return the previous state. Why the code is executed after the second click?

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

>Solution :

The behavior you’re observing is a result of how React handles state updates and rendering. Let’s break down the process step by step:

Initial render: When the component is first rendered, the counter is set to 1 and the initial state is { isActive: false }.

First click: Upon clicking the "Text caption" div for the first time, the onMouseDown handler is triggered. This handler uses the functional version of setState, which takes the previous state as an argument. It evaluates whether the isActive property is already true in the previous state. If it’s true, it returns the previous state as is; otherwise, it creates a new state object with isActive set to true.

In this instance, the initial state is { isActive: false }, so the handler returns a new state object { isActive: true }, prompting a re-render.

Second click: After the first click, the state becomes { isActive: true }. When you click the "Text caption" div again, the onMouseDown handler is triggered once more. This time, the handler receives the previous state { isActive: true }. It checks if the isActive property is already true, which it is, leading to the handler returning the unchanged previous state.

Although the returned state is the same, React still schedules a re-render because a state update was initiated. This results in the second re-render taking place.

At this point, the counter is incremented to 2.

So, the sequence of events is as follows:

  1. Initial render (counter = 1).
  2. First click -> Re-render (counter = 2).
  3. Second click -> Re-render (counter = 3).

The reason you only see "Render – 2x" in the HTML is that React groups multiple state updates occurring during a single event loop iteration. As a result, the second re-render, triggered by the second click, doesn’t immediately update the counter displayed. Instead, React batches these updates and applies them collectively in a single render cycle. Consequently, you observe the final state as "Render – 2x".

For real-time updates of the counter displayed in the rendered output with every individual state update, consider utilizing the useEffect hook to update it after each rendering cycle.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading