[英]React stale state with useEffect loop
Given the following component:给定以下组件:
import { useEffect, useState } from "react"
const Test = () => {
const [thing, setThing] = useState({ x: 0, y: 0 });
useEffect(() => {
gameLoop();
}, []);
const gameLoop = () => {
const p = {...thing};
p.x++;
setThing(p);
setTimeout(gameLoop, 1000);
}
return (
<div>
</div>
)
}
export default Test;
Every second a new line is printed into the console.每秒都会在控制台中打印一个新行。 The expected output should of course be:
预期的 output 当然应该是:
{ x: 1, y: 0 }
{ x: 2, y: 0 }
{ x: 3, y: 0 }
...etc ...ETC
What is instead printed is:而是打印的是:
{ x: 0, y: 0 }
{ x: 0, y: 0 }
{ x: 0, y: 0 }
I've come to the conclusion as this is because of a stale state.我得出结论,因为这是因为 state 过时。 Some solutions I've found and tried are:
我找到并尝试过的一些解决方案是:
Adding thing to the dependency array causes it to be called ridiculously fast.将东西添加到依赖数组会导致它被快速调用。 Adding thing.x to the array also does the same.
将 thing.x 添加到数组中也是如此。
One post I found mentioned changing the setState to look like so:我发现一篇文章提到将 setState 更改为如下所示:
setState(thing => {
return {
...thing.
x: thing.x+1,
y: thing.y
});
Which changed nothing.这没有任何改变。
I have found a lot of posts about clocks/stopwatches and how to fix this issue with primitive value states but not objects.我发现了很多关于时钟/秒表的帖子,以及如何用原始值状态而不是对象来解决这个问题。
What is my best course of action to fix the behavior while maintaining that it only runs once a second?在保持它每秒只运行一次的同时修复行为的最佳行动方案是什么?
EDIT: The comments seem to be stating I try something like this:编辑:评论似乎是说我尝试这样的事情:
import { useEffect, useState } from "react"
const Test = () => {
const [thing, setThing] = useState({ x: 0, y: 0 });
useEffect(() => {
setInterval(gameLoop, 1000);
}, []);
const gameLoop = () => {
console.log(thing)
const p = {...thing};
p.x++;
setThing(prevP => ({...prevP, x: prevP.x+1}));
}
return (
<div>
</div>
)
}
export default Test;
This still prints out incorrectly:这仍然打印不正确:
{ x: 0, y: 0 }
{ x: 0, y: 0 }
{ x: 0, y: 0 }
I think you can use this solution:我认为您可以使用此解决方案:
useEffect(() => {
setInterval(() => {
setThing((prev) => ({
...prev,
x: prev.x + 1,
}));
}, 1000);
}, []);
I suggest to control setInterval with the clearInterval when component is destroied;我建议在组件被销毁时使用 clearInterval 控制 setInterval; like this:
像这样:
useEffect(() => {
const interval = setInterval(() => {
setThing((prev) => ({
...prev,
x: prev.x + 1,
}));
}, 1000);
return () => {
clearInterval(interval);
};
}, []);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.