What is the reason for the immediate application of the set function in a useState hook within asynchronous functions?

While working with multiple set functions of a useState hook, I noticed different behaviors when calling them in sync and async functions.

function Test() {
    console.log('app rendering starts.');
    const [a, setA] = useState(1);
    const [b, setB] = useState(11);
    const updateState = () => {
        console.log('\tupdating a starts.');
        setA(2);
        console.log('\tupdating a ends.');
        console.log('\tupdating b starts.');
        setB(12);
        console.log('\tupdating b ends.');
    };
    console.log('app rendering ends.');
    return (
        <div className="App">
            <div>a is {a}</div>
            <div>b is {b}</div>
            <button onClick={() => {
                console.log('--------------sync click--------------');
                updateState();
            }}>Update State a & b Sync</button>
            <button onClick={() => {
                console.log('--------------async click--------------');
                setTimeout(updateState, 0)
            }}>Update State a & b Async</button>
        </div>
    );
}

Even though both buttons execute the same code, they produce different results.
Sync button outcome:

app rendering starts.
app rendering ends.
--------------sync click--------------
    updating a starts.
    updating a ends.
    updating b starts.
    updating b ends.
app rendering starts.
app rendering ends.

Async button outcome:

app rendering starts.
app rendering ends.
--------------async click--------------
    updating a starts.
app rendering starts.
app rendering ends.
    updating a ends.
    updating b starts.
app rendering starts.
app rendering ends.
    updating b ends.

Is this behavior intended?
How can I achieve a synchronous result in an asynchronous function?
I couldn't find any guidance on this in official documentation.
Any assistance would be greatly appreciated.
Thank you!

Answer №1

It is widely acknowledged that this information can be found in discussions on Github.

A particularly clear comment states:

React will consolidate state updates if they are initiated from within a React-based event, such as a button click or input change. Updates will not be consolidated if they are triggered outside of a React event handler, like with setTimeout().

Internally, React uses unstable_batchedUpdates(). By passing in a callback function, any state updates inside it will be consolidated. This behavior does not occur automatically for timeouts, promises, and asynchronous functions called from outside the callback.

import { unstable_batchedUpdates } from "react-dom";
const updateState = () => {
    unstable_batchedUpdates(() => {
      console.log("\tupdating a starts.");
      setA(2);
      console.log("\tupdating a ends.");
      console.log("\tupdating b starts.");
      setB(12);
      console.log("\tupdating b ends.");
    });
  };

Link to Sandbox

Answer №2

Instead of using separate state slices, it is more efficient to use a single useState() or useReducer() hook call to update multiple state values by storing them together.

const [data, setData] = useState({x: 5, y: 10});

setData({x: 7, y: 15});

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

The information retrieved from the API is not appearing as expected within the Angular 9 ABP framework

I am facing an issue with populating data in my select control, which is located in the header child component. The data comes from an API, but for some reason, it is not displaying correctly. https://i.stack.imgur.com/6JMzn.png. ngOnInit() { thi ...

Sending data through ajax to PHP on separate pages is a common practice

Here is where I choose my preferred option Company Name<br /> <select id="company" name="selected"> <option value="">Option A</option> <option value="">Option B</option> </select> When I click this, a mo ...

What sets apart the following: ( import React from "react"; ) and ( import React from 'react'; )?

When it comes to imports, is there a distinction between using single quotes (') versus double quotes ("), for example in import React from 'react'; and import React from "react";? Are there any notable differences? ...

Having trouble toggling classes with mouseup in Wordpress Underscores theme

While I'm utilizing Underscores as the foundation theme for my website, one aspect that I particularly appreciate is its incorporation of a functional mobile navigation component. However, since my site is essentially single-page, the navigation remai ...

Styling Material-ui components with makeStyles often requires the use of several instances of ( !important <= css code )

I am currently in the process of developing a website using material-ui and react. I wanted to customize the mui components with my own styles. To achieve this, I utilized the makeStyle function from '@mui'. However, I encountered an issue where ...

How to drop several pins on Google Maps with JavaScript

I am working on incorporating multiple markers into a Google map using ajax, javascript, and php. Although there are no errors in my code, the markers are not appearing as expected. I would greatly appreciate any assistance with this issue. Please refer to ...

Can a software be created to capture search results from the internet?

Is it feasible to create a program that can extract online search results? I am specifically interested in retrieving data from Some of the data I need include application numbers, such as 9078871 and 10595401 Although there are CAPTCHAs present, I am w ...

Endless rotation with stunning magnification feature

My goal is to create a responsive carousel with auto-play infinite loop functionality, where the center item always occupies 70% of the viewport width. Currently, I have achieved a similar result using the Slick library: https://codepen.io/anon/pen/pBvQB ...

How can I remove a row from an MVC webgrid using an ajax call?

Within my MVC Razor view, I have a partial view containing webgrid data. My goal is to include an action link to delete a specific row of data. To accomplish this, I crafted the following JavaScript function: function delMeal(pid) { if (confirm("Do yo ...

Error: Missing 1 type argument(s) in generic type definition

I've developed an abstract class structure as shown below: export abstract class CsvFileReader<T> { data: T[] = [] constructor(public file: string) {} abstract mapRow(row: string[]): T read() { this.data = this.file .split(& ...

Avoid running another process before the current one finishes in jQuery

I have a situation where I am using $.ajax inside a for loop in jQuery. for(var i=0; i < 2; i++) { $.ajax({ url :"/models/getdata"+i, dataType:"json", success:function(data) { } }); } The issue is that before the success function for i=0 completes, ...

Searching for parameters wrongly triggering the id on a different route

Having recently delved into mongoose, I must apologize in advance for any misuse of terminology on my part. Below is the content of my routes file: const express = require('express'); const router = express.Router(); const passport = require(&a ...

Utilize the serialized data to pre-fill the form fields

After using the serialize() function on my form and saving the string, I am now looking for a function that can repopulate values back into the form from the serialized string. Is there such a function available? ...

Building a hierarchical object structure from an array

I am working with an array of objects that looks like this: const sorted = [ { IsoCode: "EUR", Buy: 1.948, Sell: 1.963 }, { IsoCode: "GBP", Buy: 2.1184, Sell: 2.1894 }, { IsoCode: "USD", Buy: 1.5781, Sell: 1.6484 }, ] and my ...

A guide to retrieving the timezone based on a specific address using the Google API

I need to utilize the Google API time zones, which requires geocoding the address to obtain the latitude and longitude for the time zone. How can I achieve this using a value from a textarea? Here are the 2 steps: Convert the textarea value into a geoc ...

Detecting When an Input has an :invalid Selector in Jquery

Here is the code snippet I am currently working with: HTML <input type="text" data-value="1" data-type="input-records" placeholder="Value" pattern="\d{1,4}$" /> CSS input[type=text]:invalid { background-color: red; } Javascript $("[data-ty ...

Looking for a way to upload only part of a large file using HTML and PHP

Is it possible to create a PHP script that can upload only the first 1 MB of a very large file? Can this be achieved with a standard form upload in PHP by closing off the connection after 1 MB is uploaded? I have researched various uploaders (HTML5/Java ...

Exploring the array of nested objects within an array of objects

Greetings, I seem to be facing a challenge with my JSON data. My goal is to extract the "tag" value from the objects within the "cows" array. Delving into nested data structures is somewhat new to me, and I've hit a roadblock in this process. Any insi ...

Clearing the redux store when a User Logs Off

I am currently developing a fitness app and I have encountered a problem that seems like it should be easy to fix, but I just can't figure it out. The issue arises when User 1 logs out and User 2 logs in - User 2 ends up seeing User 1's workout ...

Transfer the user data to a component using React Router Dom

Having difficulty transferring the user to a page in React? I've managed to do it with my Navbar component, but I'm stuck trying to replicate it on a regular page. Using user.attributes.x like I did in the Navbar component is throwing an error. ...