为什么调用 useState 钩子的 set 函数会立即应用于异步函数?

MRN*_*siA 6 javascript reactjs react-hooks

在同步和异步函数中调用 useState 挂钩的多个设置函数时,我遇到了不同的行为。

function Test() {
    console.log('app rendering starts.');
    const [a, setA] = useState(1);
    const [b, setB] = useState(11);
    const updateState = () => {
        console.log('\tupdating a starts.');
        setA(2);
        console.log('\tupdating a ends.');
        console.log('\tupdating b starts.');
        setB(12);
        console.log('\tupdating b ends.');
    };
    console.log('app rendering ends.');
    return (
        <div className="App">
            <div>a is {a}</div>
            <div>b is {b}</div>
            <button onClick={() => {
                console.log('--------------sync click--------------');
                updateState();
            }}>Update State a & b Sync</button>
            <button onClick={() => {
                console.log('--------------async click--------------');
                setTimeout(updateState, 0)
            }}>Update State a & b Async</button>
        </div>
    );
}
Run Code Online (Sandbox Code Playgroud)

两个按钮执行相同的代码,但以不同的方式。
同步按钮结果:

app rendering starts.
app rendering ends.
--------------sync click--------------
    updating a starts.
    updating a ends.
    updating b starts.
    updating b ends.
app rendering starts.
app rendering ends.
Run Code Online (Sandbox Code Playgroud)

异步按钮结果:

app rendering starts.
app rendering ends.
--------------async click--------------
    updating a starts.
app rendering starts.
app rendering ends.
    updating a ends.
    updating b starts.
app rendering starts.
app rendering ends.
    updating b ends.
Run Code Online (Sandbox Code Playgroud)

这是期望的行为吗?
如何在异步函数中获得同步结果?
我在官方文档中找不到任何关于此的提示。
任何帮助,将不胜感激。
谢谢!

Tus*_*ahi 3

根据Github 的讨论,这似乎是一个已知的事实。

我认为其中一条评论非常不言自明:

如果状态更新是从基于 React 的事件(例如按钮单击或输入更改)中触发的,React 当前将批量状态更新。如果更新是在 React 事件处理程序之外触发的,例如 setTimeout(),它不会批量更新。

React 内部使用unstable_batchedUpdates(). 您可以传入回调函数并在其中批量更新状态。对于超时、承诺和异步函数,这不会自动发生。因此它们是从回调外部调用的,并且它们内部的状态更新不是批处理的。

import { unstable_batchedUpdates } from "react-dom";
Run Code Online (Sandbox Code Playgroud)
const updateState = () => {
    unstable_batchedUpdates(() => {
      console.log("\tupdating a starts.");
      setA(2);
      console.log("\tupdating a ends.");
      console.log("\tupdating b starts.");
      setB(12);
      console.log("\tupdating b ends.");
    });
  };

Run Code Online (Sandbox Code Playgroud)

沙盒链接