使用useEffect循环反应过时状态



给定以下组件:

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;

控制台上每隔一秒钟就会打印一行新行。预期输出当然应该是:

{ x: 1, y: 0 }
{ x: 2, y: 0 }
{ x: 3, y: 0 }

etc

取而代之的是:

{ x: 0, y: 0 }
{ x: 0, y: 0 }
{ x: 0, y: 0 }

我得出的结论是,这是因为一种陈腐的状态。我发现并尝试过的一些解决方案是:

  1. 依赖数组

向依赖数组中添加东西会导致调用速度快得离谱。将thing.x添加到数组中也可以执行同样的操作。

  1. 更改setState调用

我发现的一篇帖子提到了将setState更改为这样:

setState(thing => {
return {
...thing.
x: thing.x+1,
y: thing.y
});

这并没有改变什么。

我发现了很多关于时钟/秒表的帖子,以及如何用基元值状态而不是对象来解决这个问题。

在保持行为每秒只运行一次的同时,我的最佳操作方案是什么?

编辑:评论似乎在说我尝试了这样的东西:

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;

这仍然打印错误:

{ x: 0, y: 0 }
{ x: 0, y: 0 }
{ x: 0, y: 0 }

我认为你可以使用这个解决方案:

useEffect(() => {
setInterval(() => {
setThing((prev) => ({
...prev,
x: prev.x + 1,
}));
}, 1000);
}, []);

我建议在组件损坏时用clearInterval控制setInterval;像这样:

useEffect(() => {
const interval = setInterval(() => {
setThing((prev) => ({
...prev,
x: prev.x + 1,
}));
}, 1000);
return () => {
clearInterval(interval);
};
}, []);

最新更新