gpt4 book ai didi

javascript - 状态更新被另一个(以前的)状态更新覆盖?

转载 作者:行者123 更新时间:2023-12-05 00:24:54 25 4
gpt4 key购买 nike

我知道这似乎是一个不寻常的例子,但我似乎仍然无法准确解释为什么我从未见过 valueB单击 div 后在控制台上打印?
请注意,由于我在 setTimeout 中调用了两个设置状态调用。 , 它们未批量处理 .

function App() {
let [a, setA] = React.useState();
let [b, setB] = React.useState();

React.useEffect(() => {
console.log('Entering useEffect', a, b);

return () => {
console.log('Entering cleanup', a, b);

setA(null);
setB(null);
};
}, [a, b]);

console.log('Render', a, b);

return (
<div
onClick={() => {
setTimeout(() => {
setA('valueA');
setB('valueB');
}, 100);
}}
>
<h1>Test App</h1>
</div>
);
}

ReactDOM.render(
<App/>,
document.getElementById("react")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.1/umd/react-dom.production.min.js"></script>
<div id="react"></div>

最佳答案

通常 useEffect并且它的清理在渲染后被异步调用(在另一个堆栈上)。但是,如果您调用 setState在计时器中,有useEffect回调,它们被急切地调用,但所有从清理累积的状态变化被称为 之后 setState调用了这个操作。
所以在你的例子中setTimeout处理程序被称为:

  • 调用setA时: a状态已更改,清理中的两个状态更改添加到待处理状态更改队列
  • 调用setB时: 第一个 valueB应用于b然后 null来自清理(这里有点批处理)

  • 当状态更新像在点击处理程序中那样实际被批处理时,这试图模仿行为(首先从点击处理程序应用状态更新,然后从 useEffect 应用状态更新)。
    当您使用更新函数时,您可以更清楚地看到发生了什么:

    function App() {
    Promise.resolve().then(() => console.log("**** another stack ****"));
    console.log("before useStateA");
    let [a, setA] = React.useState();
    console.log("between useStates");
    let [b, setB] = React.useState();
    console.log("after useStateB");


    React.useEffect(() => {
    console.log('Entering useEffect', a, b);

    return () => {
    console.log('Entering cleanup', a, b);

    setA(() => (console.log("setting a to null from cleanup"), null));
    setB(() => (console.log("setting b to null from cleanup"), null));
    };
    }, [a, b]);

    console.log('Render', a, b);

    return (
    <div
    onClick={() => {
    setTimeout(() => {
    console.log("****timer start****");
    setA(() => (console.log("setting a to valueA from timer"), "valueA"));
    console.log("between timer setters");
    setB(() => (console.log("setting b to valueB from timer"), "valueB"));
    console.log("****timer end****");
    }, 100);
    }}
    >
    <h1>Test App</h1>
    </div>
    );
    }

    ReactDOM.render(
    <App/>,
    document.getElementById("react")
    );
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.1/umd/react.production.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.1/umd/react-dom.production.min.js"></script>
    <div id="react"></div>

    关于javascript - 状态更新被另一个(以前的)状态更新覆盖?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68080085/

    25 4 0
    文章推荐: javascript - 与基础版本 SES 相比,SESv2 的 aws-sdk 是否缺少某些功能?
    文章推荐: javascript - HTML