在 React 中使用 useState 和 useEffect 的无限循环

Infinity loop using useState with useEffect in React

我想在每一秒后增加状态[second] = [second + 1]。

const [second,setSecond] = useState(0);
useEffect(() => {
    const interval = setInterval(() => {
      setSecond(second+1)
    }, 1000);
    return () => clearInterval(interval);
}, []);

但是好像出现了无限循环,[second]只增加了一次,从0到1,就停止了运行。

我更改了我的代码

setSecond(second+1)

setSecond((second) => {return second+1})

这个运行没有问题:

const [second,setSecond] = useState(0);
useEffect(() => {
    const interval = setInterval(() => {
      setSecond((second) => {return second+1})
    }, 1000);
    return () => clearInterval(interval);
}, []);

说真的,我还是没看清楚。谁能向我解释为什么?提前致谢!

查看您的代码,我认为问题在于 second 的值被绑定为 0。

const [second,setSecond] = useState(0);
useEffect(() => {
    const interval = setInterval(() => {
      setSecond(second+1)
    }, 1000);
    return () => clearInterval(interval);
}, []);

这里当你的组件挂载时,useEffect 被执行。那时您正在创建一个函数并将其传递给 setInterval。此函数将在创建时使用 second 的值(等于 0)。因此,每次运行 setInterval 时,它都会执行 setSecond(0+1),它始终等于 1.

你提到的正确方法是有效的,因为你给它一个函数,每次执行时都会将状态的当前值传递给它。

再见,你设置second的两种方式不一样。

这样:

setSecond(second+1)

不考虑second的先前值。它只是尝试通过读取 second 的当前值将秒加 1。考虑到 setSecond 是异步的,在下一个 setInterval 上不能保证 second 会被前一个 setSecond 更新。所以这样你可能会出现故障。

这样:

setSecond((second) => {return second+1})

是正确的。在这里,您正在考虑 second 的先前值(通过使用箭头函数)。所以在这种情况下,second 将被正确更新。

你可以做一个测试:拿一个按钮,然后在 onclick 函数上尝试写:

setSecond(second+1)
setSecond(second+1)

您会看到 second 将增加 1(而不是预期的 2)。

现在像这样修改你的代码:

setSecond((second) => {return second+1})
setSecond((second) => {return second+1})

你会看到 second 会增加 2!

发生这种情况是因为 Hooks 是异步的。