为什么 Async Await 与 React setState 一起工作? [英] Why does Async Await work with React setState?

查看:29
本文介绍了为什么 Async Await 与 React setState 一起工作?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在我的 ReactJS 项目中使用 async await 和 babel.我发现了 React setState 的一个方便用法,我只是想更好地理解它.考虑这个代码:

handleChange = (e) =>{this.setState({[e.target.name]: e.target.value})console.log('同步代码')}changeAndValidate = async (e) =>{等待 this.handleChange(e)console.log('异步验证码')}componentDidUpdate() {console.log('更新的组件')}

我的目的是让异步验证代码在组件更新后运行.它有效!结果控制台日志显示:

同步代码更新组件异步验证码

只有在 handleChange 更新状态并呈现新状态后,验证代码才会运行.

通常要在状态更新后运行代码,您必须在 this.setState 之后使用回调.这意味着如果你想在 handleChange 之后运行任何东西,你必须给它一个回调参数,然后传递给 setState.不漂亮.但是在代码示例中,不知何故, await 在状态更新后知道 handleChange 已完成...但我认为 await 仅适用于承诺并在继续之前等待承诺解决.handleChange 中没有承诺也没有解决方案……它怎么知道要等待什么??

这意味着 setState 是异步运行的,而 await 以某种方式知道它何时完成.也许 setState 在内部使用了 Promise?

版本:

反应:^15.4.2"

babel 核心:^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"

解决方案

我已尽力简化和补充 Davin 的答案,以便您更好地了解此处实际发生的情况:

<小时>

  1. await 放在this.handleChange 的前面,这将安排 其余changeAndValidate 的执行> 函数仅在 await 解析右侧指定的值时运行,在本例中为 this.handleChange 返回的值莉>
  2. this.handleChange,在await的右边,执行:

    2.1.setState 运行其更新程序,但由于 setState 不保证立即更新,因此它可能会安排更新在以后发生(没关系如果它是立即的或稍后的时间点,重要的是它被安排了)

    2.2.console.log('同步代码') 运行...

    2.3.this.handleChange 然后退出返回 undefined (返回 undefined 因为函数返回 undefined 除非明确指定)

  3. await 然后接受这个 undefined 并且由于它不是承诺,所以它使用 Promise.resolve(undefined)<将其转换为已解决的承诺/strong> 并等待它 - 它不是立即可用的,因为在幕后它被传递给它的异步 .then 方法:

<块引用>

传入承诺的回调永远不会在完成 JavaScript 事件循环的当前运行"

3.1.这意味着 undefined 将被放入事件队列的后面,(这意味着它现在在我们的事件队列中的 setState 更新器后面......)

  1. 事件循环最终到达并获取我们的setState更新,它现在执行...

  2. 事件循环到达并拾取undefined,其计算结果为undefined (如果需要,我们可以存储它,因此通常在 await 前面使用 = 来存储解析结果)

    5.1.Promise.resolve() 现已完成,这意味着 await 不再有效,因此其余函数可以继续

  3. 您的验证代码运行

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"

解决方案

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

这篇关于为什么 Async Await 与 React setState 一起工作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆