javascript - 如果在事件处理程序之前或之间有等待调用,React 不会在事件处理程序中批处理 setState 调用

标签 javascript reactjs async-await react-hooks setstate

我发现了这个有趣的 React 行为,我想了解更多。

通常 React 会在事件处理程序中批处理多个 setState() 调用,对吗?

但我测试过 React 在以下情况下不会批处理调用:

  • 事件处理函数是一个带有 await 调用的 async 函数。
  • await 调用在 setState() 调用之前或之间执行。
    • 如果 awaitsetState() 调用之后运行,它们将照常进行批处理。

问题:

你知道这背后的原因是什么吗?


代码沙箱: https://codesandbox.io/s/eventhandlerawaitso-jsdxs

这是mockAPI调用

function mockAPI() {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve("I come from API using an AWAIT call");
      },500);
    });
  }

这些是要测试的处理程序:

function handleClickNormal() {
    console.clear();

    console.log("Calling 1st setState()");
    updateBooleanState(false);

    console.log("Calling 2nd setState()");
    updateBooleanState(true);

    console.log("After 2nd setState()");
  }

  async function handleClickAwaitBefore() {
    console.clear();

    // AWAIT CALL RUNS BEFORE THE setState CALLS
    const fromAPI = await mockAPI();
    console.log(fromAPI);

    console.log("Calling 1st setState()");
    updateBooleanState(false);

    console.log("Calling 2nd setState()");
    updateBooleanState(true);

    console.log("After 2nd setState()");
  }

  async function handleClickAwaitAfter() {
    console.clear();

    console.log("Calling 1st setState()");
    updateBooleanState(false);

    console.log("Calling 2nd setState()");
    updateBooleanState(true);

    console.log("After 2nd setState()");

    // AWAIT CALL RUNS AFTER THE setState CALLS
    const fromAPI = await mockAPI();
    console.log(fromAPI);
  }

  async function handleClickAwaitBetween() {
    console.clear();

    console.log("Calling 1st setState()");
    updateBooleanState(false);

    // AWAIT CALL RUNS BETWEEN THE setState CALLS
    const fromAPI = await mockAPI();
    console.log(fromAPI);

    console.log("Calling 2nd setState()");
    updateBooleanState(true);

    console.log("After 2nd setState()");
  }

这是结果:

enter image description here

评论

如果没有 await 调用,我们可以看到setState() 调用是批处理的(单击“正常”) 并且如果 await 调用在 setState() 之后 (单击 Await After)。

如果 await 调用 before (单击 Await Before),则 setState() 调用不会被批处理之间 setState() 调用(单击 Await Between)。

最佳答案

异步编程在很大程度上与调用堆栈和事件循环有关。
您可以在此视频中找到很多相关信息:https://www.youtube.com/watch?v=8aGhZQkoFbQ

因此,当您在两者之间有 await 时,setState 将落入不同的堆栈。
我相信这是 React 不对它们进行批处理的主要原因。

关于javascript - 如果在事件处理程序之前或之间有等待调用,React 不会在事件处理程序中批处理 setState 调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56581542/

相关文章:

javascript - 使用JavaScript获取HTML表单值并将其保存到JSON键和值对中

javascript - 在 contentEditable div 中使用 jQuery 清理粘贴事件

javascript - Reduxjs 或简单地声明

java - 我可以在 Oracle 的 JDK7 JSR223 JavaScript 引擎中扩展 Java 类吗?

javascript - Angular : parent directive isn't affected by changes in its child

javascript - 如何使用钩子(Hook)在 react 中切换单选按钮的选中值?

javascript - 当元素类未知时如何获取元素的工厂

.net - 如何将 CancellationToken 与 Tasks.WaitAll() 一起使用

c# - IObservable 与 NetMQ 接收

c# - 如何知道任务是否同步完成?