是否在异步事件处理程序中批处理setState更新?

时间:2020-06-07 18:18:04

标签: javascript reactjs async-await dom-events setstate

根据我在react版本16(当前)及以下版本中的了解,setState调用是成批的IFF,它们是在组件生命周期事件或事件处理程序中进行的。否则,为了进行批量呼叫,可以使用ReactDOM.unstable_batchedUpdates中的opt。

如果事件处理程序是async函数,则浏览器将触发该事件处理程序,但是将返回一个promise,因此,实际的事件处理程序Promise回调将直到运行接下来的微任务在事件循环中被拾取。换句话说,setState更新实际上不会在立即事件处理程序中发生。

这是否意味着如果我们要在事件处理程序中分批ReactDOM.unstable_batchedUpdates更新,就需要选择加入setState

2 个答案:

答案 0 :(得分:1)

以下调用将由React进行批量处理,并将导致一次重新渲染。

const onClick = (e) => {
    setHeader('Some Header');
    setTitle('Some Tooltip');
};

如果没有ReactDOM.unstable_batchedUpdates,React会进行2次sync调用来重新渲染组件。现在,它将使用此API进行一次重新渲染。

const onClick = (e) => {
    axios.get('someurl').then(response => {
        ReactDOM.unstable_batchedUpdates(() => {
            setHeader('Some Header');
            setTitle('Some Tooltip');
        });
    });
};

附加说明:

  1. 我们在项目中使用过一次,并且工作无缝。但是我个人更喜欢将状态作为对象并立即更新事物,而不是这种方法。但我知道这并不总是可能的。
  2. Here,我们可以看到它处于实验模式,因此不确定是否应在生产中使用它。

更新

基于OP注释,以下是JavaScript中异步等待的版本。

const onClick = async e => {

  setState(1);
  setState(2);
  await apiCall();

  ReactDOM.unstable_batchedUpdates(() => {
      setState(3);
      setState(4);
  });
}

以上代码将触发重新渲染两次。一次更新1/2,另一个更新3/4。

答案 1 :(得分:0)

经过研究,我相信答案是async事件处理程序的 initial 部分(最终转换为返回的Promise的执行函数)幕后)将批处理setState个更新,但在进行任何await调用后都不会更新。

这是因为async函数主体中的所有内容,在第一个await之前的中,都转换为执行程序函数,该函数在事件的浏览器事件处理程序中执行,但是之后的所有内容最终都变成了初始执行程序函数的链式Promise回调,并且这些链式回调在微任务队列上执行。

这是因为async () => {}被翻译成类似return new Promise().then()的东西,其中每个await都是在const onClick = async e => { // 1 and 2 will be batched setState(1) setState(2) await apiCall() // 3 and 4 will not be batched setState(3) setState(4) } 语句之后为代码创建的回调。

P2_CLIENT_ID