我在ReactJS项目中使用了async wait with 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更新了状态并呈现了新状态之后才运行。
通常要在state更新后运行代码,必须在this. setState之后使用回调。这意味着如果要在handleChange之后运行任何内容,必须为其给予一个回调参数,然后将其传递给setState。这并不美观。但在代码示例中,不知何故,wait知道handleChange在状态更新后完成...但是我认为wait只适用于承诺,并等待承诺解决后再继续。handleChange中没有承诺,也没有解决方案...它怎么知道该等待什么?
其含义似乎是setState异步运行,await不知何故知道它何时完成。也许setState在内部使用promise?
版本:
React:“^15.4.2”
巴伯尔-核心:“^6.26.0”
标签预设环境:“^1.6.0”,
Babel-预设-React:“^6.24.1”,
巴伯尔预设阶段0:“^6.24.1”
标签-插件-系统-导入-转换器:“^3.1.0”,
babel插件转换装饰器遗留:“^1.3.4”,
babel插件转换运行时:“^6.23.0”
5条答案
按热度按时间ebdffaop1#
我尽力简化和补充达文的回答,这样你就能更好地了解实际情况:
1.await放置在this.handleChange之前,这将调度changeAndValidate函数其余部分的执行,使其仅在await*解析它右侧指定的值时运行,在本例中,解析this.handleChange返回的值
1.wait右侧的this.handleChange执行:
2.1.setState运行其更新程序,但由于setState不保证立即更新,它可能会将更新计划在稍后时间进行***(立即更新或在稍后时间点更新并不重要,重要的是已计划更新)***
2.2. console.log(“同步代码”)运行...
2.3.this.handleChange然后退出,返回undefined*(返回undefined,因为函数返回undefined,除非另外显式指定)*
1.await然后接受这个undefined,由于它不是一个承诺,它使用Promise.resolve(undefined)将其转换为一个已解析的承诺,并等待它-它不是立即可用的,因为在后台它被传递给它的.then方法,这是异步的:
“在JavaScript事件循环的当前运行完成之前,将永远不会调用传入承诺的回调”
3.1.这意味着undefined将被放置在事件队列的后面,(这意味着它现在在事件队列中的setState更新器后面...)
1.事件循环最终到达并拾取我们的setState更新,该更新现在执行...
1.事件循环到达并拾取undefined,其计算结果为undefined*(如果需要,我们可以存储它,因此通常在await前面使用=来存储解析结果)*
5.1.Promise.resolve()现在已完成,这意味着await不再有效,因此函数的其余部分可以继续
1.您的验证代码运行
gpfsuwkq2#
我还没有对此进行测试,但我认为这是正在发生的事情:
await
返回的undefined
在setState
回调之后排队。await
正在下面(在regenerator-runtime
中)执行Promise.resolve
,这反过来又将控制权交给事件循环中的下一项。因此,
setState
回调恰好排在await
之前,这是巧合。您可以通过在
setState
周围放置setTimeout(f =〉f,0)来测试这一点。babel
中的regenerator-runtime
本质上是一个使用Promise.resolve
产生控制的循环。你可以看到_asyncToGenerator内部,它有一个Promise.resolve
。f87krz0w3#
setState()
并不总是立即更新组件文档但这里可能就是这样。
如果你想用承诺来代替回调,你可以自己实现它:
参考:https://medium.com/front-end-hacking/async-await-with-react-lifecycle-methods-802e7760d802
9vw9lbht4#
await的
rv
或返回值定义为:由于handleChange不是一个异步值或承诺值,它只是返回自然值(在本例中,没有返回,因此
undefined
).因此,这里没有异步事件循环触发器来“让它知道handleChange已完成”,它只是按照您给它的顺序运行.qnyhuwrf5#
举个简单的例子:在
test-02
中,代码await this.setState({ a: 10 });
实际上,等于test-03
中的this.setState({ a: 10 }); await undefined;
。并且await undefined;
导致其背后的代码在下一个事件循环中执行。