Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does Async Await work with React setState?

I have been using async await with babel in my ReactJS project. I discovered a convenient use with React setState that I would just like to understand better. Consider this code:

handleChange = (e) => {   this.setState({[e.target.name]: e.target.value})   console.log('synchronous code') }  changeAndValidate = async (e) => {   await this.handleChange(e)   console.log('asynchronous validation code') }  componentDidUpdate() {   console.log('updated component')     } 

My intention was for the asynchronous validation code to run after the component has updated. And it works! The resulting console log shows:

synchronous code updated component asynchronous validation code 

The validation code will only run after handleChange has updated the state and the new state is rendered.

Usually to run code after state has updated, you would have to use a callback after this.setState. Which means if you want to run anything after handleChange, you have to give it a callback parameter which is then passed to setState. Not pretty. But in the code example, somehow await knows that handleChange is complete after the state has updated... But I thought await only works with promises and waits for a promise to resolve before continuing. Theres no promise and no resolution in handleChange... How does it know what to wait for??

The implication seems to be that setState is run asynchronously and await is somehow aware of when it completes. Maybe setState uses promises internally?

Versions:

react: "^15.4.2"

babel-core: "^6.26.0"

babel-preset-env: "^1.6.0",

babel-preset-react: "^6.24.1",

babel-preset-stage-0: "^6.24.1"

babel-plugin-system-import-transformer: "^3.1.0",

babel-plugin-transform-decorators-legacy: "^1.3.4",

babel-plugin-transform-runtime: "^6.23.0"

like image 628
Leo Fabrikant Avatar asked Oct 30 '17 15:10

Leo Fabrikant


People also ask

Can we use async await in setState React?

The setState function also does not return a Promise. Using async/await or anything similar will not work.

Why React setState is async?

Why setState() is async? ReactJs sets its state asynchronously because it can result in an expensive operation. Making it synchronous might leave the browser unresponsive. Asynchronous setState calls are batched to provide a better user experience and performance.

How many arguments does setState take and why is it async?

The setState method takes up to 2 arguments. We usually pass in only one. The first argument can be an object or a callback that's used to update the state. which calls setState once, and then calls setState again in the callback.

How do you use await in setState in React JS?

Take a simple example: in the test-02 , the code await this. setState({ a: 10 }); In fact, is equal to this. setState({ a: 10 }); await undefined; in the test-03 . And await undefined; causes the code behind it to be executed in the next event loop.


1 Answers

I tried to do my best to simplify and complement Davin's answer, so you can get a better idea of what is actually going on here:


  1. await is placed in front of this.handleChange, this will schedule the execution of the rest of changeAndValidate function to only run when await resolves the value specified to the right of it, in this case the value returned by this.handleChange
  2. this.handleChange, on the right of await, executes:

    2.1. setState runs its updater but because setState does not guarantee to update immediately it potentially schedules the update to happen at a later time (it doesn't matter if it's immediate or at a later point in time, all that matters is that it's scheduled)

    2.2. console.log('synchronous code') runs...

    2.3. this.handleChange then exits returning undefined (returns undefined because functions return undefined unless explicitly specified otherwise)

  3. await then takes this undefined and since it's not a promise it converts it into a resolved promise, using Promise.resolve(undefined) and waits for it - it's not immediately available because behind the scenes it gets passed to its .then method which is asynchronous:

“Callbacks passed into a promise will never be called before the completion of the current run of the JavaScript event loop”

3.1. this means that undefined will get placed into the back of the event queue, (which means it’s now behind our setState updater in the event queue…)

  1. event loop finally reaches and picks up our setState update, which now executes...

  2. event loop reaches and picks up undefined, which evaluates to undefined (we could store this if we wanted, hence the = commonly used in front of await to store the resolved result)

    5.1. Promise.resolve() is now finished, which means await is no longer in affect, so the rest of the function can resume

  3. your validation code runs
like image 101
linasmnew Avatar answered Oct 08 '22 18:10

linasmnew