可能会出现问题,具体取决于您的 setter 被调用的速度/频率。
如果您使用的是从闭包中获取值的简单方法,则两次渲染之间的后续调用可能不会达到预期的效果。
一个简单的例子:
function App() {
const [counter, setCounter] = useState(0);
const incWithClosure = () => {
setCounter(counter + 1);
};
const incWithUpdate = () => {
setCounter(oldCounter => oldCounter + 1);
};
return (<>
<button onClick={_ => { incWithClosure(); incWithClosure(); }}>
Increment twice using incWithClosure
</button>
<button onClick={_ => { incWithUpdate(); incWithUpdate(); }}>
Increment twice using incWithUpdate
</button>
<p>{counter}</p>
</>);
}
两个按钮都调用了两次增量方法之一。但我们观察到:
- 第一个按钮只会将计数器增加 1
- 第二个按钮将使计数器增加 2,这可能是所需的结果。
这什么时候可以发生?
- 显然,如果
incWithClosure
在彼此之后立即被多次调用
- 如果涉及异步任务,这很容易发生(见下文)
- 也许,如果 React 有很多工作要做,它的调度算法可能会决定使用相同的事件处理程序处理多次非常快速的点击
异步工作示例(模拟加载资源):
function App() {
const [counter, setCounter] = useState(0);
const incWithClosureDelayed = () => {
setTimeout(() => {
setCounter(counter + 1);
}, 1000);
};
const incWithUpdateDelayed = () => {
setTimeout(() => {
setCounter((oldCounter) => oldCounter + 1);
}, 1000);
};
return (
<>
<button onClick={(_) => incWithClosureDelayed()}>
Increment slowly using incWithClosure
</button>
<button onClick={(_) => incWithUpdateDelayed()}>
Increment slowly using incWithUpdate
</button>
<p>{counter}</p>
</>
);
}
单击第一个按钮两次(在一秒内)并观察计数器仅增加 1。第二个按钮具有正确的行为。