gio*_*gim 6 javascript reactjs react-hooks
我知道这似乎是一个不寻常的例子,但我似乎仍然无法准确解释为什么我在单击 div 后从未在控制台上看到valueB打印出来?
请注意,由于我在 a 中调用了两个 set state 调用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")
);Run Code Online (Sandbox Code Playgroud)
<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>Run Code Online (Sandbox Code Playgroud)
通常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")
);Run Code Online (Sandbox Code Playgroud)
<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>Run Code Online (Sandbox Code Playgroud)