考虑以下代码:
import React, { useState } from "react";
function App() {
const [counter, setCounter] = useState(0);
function handleClick() {
setCounter(counter + 1); // update counter without using a callback
}
return (
<div>
<button type="button" onClick={() => handleClick()}>
increase counter
</button>
<div>counter is {counter}</div>
</div>
);
}
export default App;
我是 React 的新手,听说如果一个状态应该基于它之前的值,我必须使用回调来更新状态。出于学习目的,我故意做了相反的事情:在不使用回调的情况下更新状态。我尽可能快地多次单击“增加计数器”按钮,但没有注意到任何问题。好像算对了。所以:
counter
最终只有 9 次?答案 0 :(得分:4)
考虑它的最好方法是您是否希望它围绕变量的当前值进行闭包。例如,玩这个:
function handleClick() {
setCounter(counter + 1);
setCounter(counter + 1);
}
您可能期望它是 2
,但它是 1
!这是因为两个调用都是setCounter(0 + 1)
。但是,如果您这样做了:
function handleClick() {
setCounter(c => c + 1);
setCounter(c => c + 1);
}
你确实得到了 2
。这是因为当每个 setCounter
函数运行时,它都会调用当前状态的回调(而不是它关闭的值)。
这是一个非常简单的例子,但现在考虑执行几个异步获取调用,如果不使用回调,可能会用另一个调用的状态覆盖一个调用!
const [data, setData] = useState({})
useEffect(() => {
fetch("http://example.resource")
.then(res => res.json())
.then(res => {
setData({...data, res})
});
fetch("http://another.example.resource")
.then(res => res.json())
.then(res => {
setData({...data, res})
});
}, []);
在本例中,无论哪个 fetch
第二次返回都会破坏第一次返回的数据,因为它将使用过时的 data
引用。