我刚开始学习React,在" Series of state update "一节中我对异步延迟在状态更新期间的工作方式感到困惑,例如:
export default function RequestTracker() {
const [pending, setPending] = useState(0);
const [completed, setCompleted] = useState(0);
async function handleClick() {
setPending(p=>p + 1);
await delay(pending*3000);
setPending(p=>p - 1);
setCompleted(c=>c + 1);
}
我认为这段代码将设置挂起为(pending+1),并在3秒后减少1。然而,当我点击按钮时,"pending"没有增加,"complete"值立即增加,这意味着没有延迟,"pending"值始终为0。
然后我将延迟函数改为**pending*3000+3000**
代码按照我的预期工作(将挂起设置为(pending+1)并在3秒后减少1)
这意味着'pending'值没有保持在0。你能解释在两种情况下挂起的值是如何不同的吗?
对setPending
的调用不会改变pending
的值:它不能,因为它没有办法关闭变量。pending
值与调用RequestTracker
函数时返回的值相同。
因为每次你的组件被渲染时,RequestTracker
都会被再次调用,你会得到pending
改变的错觉,因为下一次你的组件被渲染时,useState
会被再次调用,而这次它会返回之前你调用setPending
时传递的值。
但是当你在调用setPending
之后立即检查pending
的值时,你仍然会看到它在调用之前的值。有几种方法可以解决这个问题。这里有一个:
async function handleClick() {
const newPendingValue = pending + 1;
setPending(newPendingValue);
await delay(newPendingValue*3000);
setPending(p=>p - 1);
setCompleted(c=>c + 1);
}
请注意,由于异步延迟,以后调用setPending
和setCompleted
使用函数仍然是一个好主意:它们需要知道pending
和completed
在调用时的值,而不是调用处理程序的时间。
另外:您可能会尝试在提供给setPending
的函数中捕获p
的值,并在稍后使用该值,但是您传递给setPending
的函数不一定会被同步调用,因此这不是一种可靠的方法。