不可能在React中的简单递归函数中使用设置状态来增加计数器

问题描述 投票:0回答:1

我知道 setState 是异步的,但它是否显式等待所有其他代码在完成之前执行(甚至带有延迟的 setTimeout)?

我一直在尝试使用 React 中的简单递归函数来增加计数器,但 setState 从未执行。我添加了一个延迟一秒的setTimeout,只是为了给setState足够的时间来执行,但它只是无限等待,永远不会执行。

用 useRef 替换 useState 是最好的解决方案,还是有更优雅的解决方案?

import { useState } from 'react';

const TestComponent = () => {

const [counter, setCounter] = useState(1);

const setStateTest = () => {        
    setCounter(prev => prev + 1); // this line of code never executes
    setTimeout(() => {
        if (counter < 10) {
            setStateTest(); // this recursion happens infinitely because counter is never incremented
            console.log(counter); // the logged value is always 1, no incrementing
        }
    }, 1000)
}

return <button onClick={setStateTest}>Set State Test</button>

}
reactjs asynchronous recursion counter setstate
1个回答
0
投票

不要为此使用递归。

我怀疑问题是围绕原始

counter
值的闭包。 状态本身可能正在更新,但您没有将当前状态记录到控制台。 您正在记录首次调用该函数时捕获的该状态的值。 (再次单击按钮,观察更新后的值与持续的原始值一起记录到控制台。)

不要递归,而是依靠

useEffect
。 例如,考虑这种方法:

useEffect(() => {
  console.log(counter);
  const x = setTimeout(() => {
    setCounter(prev => prev + 1);
  }, 1000);
  return () => clearTimeout(x);
}, [counter]);

任何时候

counter
发生变化,该效果都会执行。 所有这些效果的作用是:

  1. counter
    的值记录到控制台
  2. 设置超时时间,1秒内更新计数器的值
  3. 返回一个函数来清除超时(这很重要,这样效果就不会泄漏资源)

然后要最初触发它,只需更新一次状态:

<button onClick={() => setCounter(prev => prev + 1)}>Set State Test</button>

一旦状态发生改变,效果就会触发,并且只要组件被加载,它就会每秒重新触发一次(通过更新其依赖数组中的状态值)。

© www.soinside.com 2019 - 2024. All rights reserved.