Reactjs 为什么Async Wait与React setState一起工作?

Reactjs 为什么Async Wait与React setState一起工作?,reactjs,async-await,babeljs,Reactjs,Async Await,Babeljs,在我的ReactJS项目中,我一直在使用AsyncWait和babel。我发现React setState有一个方便的用法,我只是想更好地理解它。考虑这个代码: handleChange = (e) => { this.setState({[e.target.name]: e.target.value}) console.log('synchronous code') } changeAndValidate = async (e) => { await this.han

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

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')    
}
我的意图是在组件更新后运行异步验证代码。而且它有效!生成的控制台日志显示:

synchronous code
updated component
asynchronous validation code
验证代码仅在handleChange更新状态并呈现新状态后运行

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

这似乎意味着setState是异步运行的,而wait在某种程度上知道它何时完成。也许setState在内部使用承诺

版本:

反应:“^15.4.2”

巴别塔核心:“^6.26.0”

巴别塔预设环境:“^1.6.0”

巴别塔预设反应:“^6.24.1”

巴别塔-preset-stage-0:“^6.24.1”

babel插件系统导入转换器“^3.1.0”

babel插件转换装饰程序传统:“^1.3.4”


babel插件转换运行时:“^6.23.0”

等待的
rv
或返回值定义为:

rv
Returns the fulfilled value of the promise, or the value itself if it's not a Promise.
因此,由于handleChange不是异步或承诺值,它只是返回自然值(在本例中,没有返回,因此
未定义
)。因此,这里没有异步事件循环触发器“让它知道handleChange已经完成”,它只是按照您给定的顺序运行

setState()
并不总是立即更新组件

但这里可能是这样

如果您想用承诺替换回调,您可以自己实现它:

setStateAsync(state) {
  return new Promise((resolve) => {
    this.setState(state, resolve)
  });
}

handleChange = (e) => {
  return this.setStateAsync({[e.target.name]: e.target.value})
}

ref:

我还没有测试过,但我认为这是正在发生的事情:

wait
返回的
undefined
setState
回调后排队。
await
正在执行下面的
Promise.resolve
(在
再生器运行时
中),这反过来会产生对事件循环上下一项的控制

因此,
setState
回调恰好在
wait
之前排队,这是巧合

您可以通过在
setState
周围放置一个setTimeout(f=>f,0)来测试这一点

babel
中的
再生器运行时
本质上是一个使用
Promise.resolve
来产生控制的循环。你可以看到的内部,它有一个
承诺。解决

我尽力简化和补充Davin的答案,这样你就可以更好地了解这里到底发生了什么:
  • wait放在前面。handleChange,这将安排其余更改和验证功能的执行,仅在wait解析其右侧指定的值时运行,在这种情况下,this.handleChange返回的值
  • 此.handleChange位于wait右侧,执行:

    2.1setState运行其更新程序,但由于setState不能保证立即更新,因此它可能会将更新安排在稍后的时间(无论是立即更新还是在稍后的时间点更新,重要的是它的计划时间)

    2.2。console.log(“同步代码”)正在运行

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

  • 等待然后接受这个未定义的,因为它不是承诺,所以使用承诺将其转换为已解决的承诺。解决(未定义)并等待它-它不是立即可用的,因为在幕后它被传递到它的。然后是异步的方法:

  • “传递到承诺中的回调将永远不会在 “JavaScript事件循环当前运行的完成”

    3.1。这意味着未定义的将被放入事件队列的后面(这意味着它现在位于事件队列中的setState更新程序后面…)

  • 事件循环最终到达并获取我们的设置状态更新,该更新现在执行

  • 事件循环到达并拾取未定义的,该循环的计算结果为未定义的(如果需要,我们可以存储该循环,因此在等待存储解析结果之前常用的=值)

    5.1Promise.resolve()现在完成,这意味着wait不再生效,因此函数的其余部分可以恢复

  • 您的验证代码将运行

  • 上面的代码在
    undefined
    上有一个
    wait
    (因为
    handleChange
    不返回任何内容)。你确定它对设置状态有影响吗?你使用的是什么版本的React和babel?这很奇怪,但我确认等待生效<代码>等待这个.setState({data:true},()=>console.log('callback');log('inline')
    明确表示将首先触发
    回调
    ,但是-remove wait并按照通常设置的方式工作-假设工作-
    内联
    ,然后
    回调
    @davintroon似乎正确