在异步代码中仍然需要函数更新语法的主要场景是。想象一下
useEffect
使用效果
下面的例子模拟了这个场景,通过一个按钮点击触发两个不同的异步进程,它们在不同的时间完成。一个按钮立即更新计数;一个按钮在不同时间触发两个异步增量而不使用函数更新语法(Naive按钮);最后一个按钮在不同时间触发两个异步增量而使用函数更新语法(Robust按钮)。
您可以在CodeSandbox中使用它来查看效果。
import React, { useState, useEffect } from "react";
import ReactDOM from "react-dom";
function App() {
const [count, setCount] = useState(1);
const [triggerAsyncIndex, setTriggerAsyncIndex] = useState(1);
const [triggerRobustAsyncIndex, setTriggerRobustAsyncIndex] = useState(1);
useEffect(
() => {
if (triggerAsyncIndex > 1) {
setTimeout(() => setCount(count + 1), 500);
}
},
[triggerAsyncIndex]
);
useEffect(
() => {
if (triggerAsyncIndex > 1) {
setTimeout(() => setCount(count + 1), 1000);
}
},
[triggerAsyncIndex]
);
useEffect(
() => {
if (triggerRobustAsyncIndex > 1) {
setTimeout(() => setCount(prev => prev + 1), 500);
}
},
[triggerRobustAsyncIndex]
);
useEffect(
() => {
if (triggerRobustAsyncIndex > 1) {
setTimeout(() => setCount(prev => prev + 1), 1000);
}
},
[triggerRobustAsyncIndex]
);
return (
<div className="App">
<h1>Count: {count}</h1>
<button onClick={() => setCount(count + 1)}>Increment Count</button>
<br />
<button onClick={() => setTriggerAsyncIndex(triggerAsyncIndex + 1)}>
Increment Count Twice Async Naive
</button>
<br />
<button
onClick={() => setTriggerRobustAsyncIndex(triggerRobustAsyncIndex + 1)}
>
Increment Count Twice Async Robust
</button>
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
另一个可能需要功能更新的场景是,如果多个效果正在更新状态(即使是同步的)。一旦一个效果更新了状态,另一个效果就会看到过时的状态。在我看来,这种场景比异步场景更不可能出现(在大多数情况下,这似乎是一个糟糕的设计选择)。