繁体   English   中英

使用 useEffect 循环反应陈旧的 state

[英]React stale state with useEffect loop

给定以下组件:

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;

每秒都会在控制台中打印一个新行。 预期的 output 当然应该是:

{ 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 }

我得出结论,因为这是因为 state 过时。 我找到并尝试过的一些解决方案是:

  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);
    };
  }, []);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM