代码之家  ›  专栏  ›  技术社区  ›  It worked yesterday.

当在useffect中调用setinterval时会发生什么

  •  -1
  • It worked yesterday.  · 技术社区  · 6 年前

    我有以下反应成分。

    function App() {
    
      const [counter, setCounter] = useState(0);
    
      useEffect(() => {
        setInterval(() => {
          setCounter(counter+1)
        }, 3000)
      }, [counter]);
    
      console.log(counter)
    
    
      return (
        <div>
          hi
        </div>
      );
    }
    
    export default App;
    

    我得到的结果是

    1个

    1个

    1个

    2个

    三 …

    我知道每次setcounter调用都会重新呈现组件,每次呈现都会重新创建useffect回调。我的问题是不应该通过

    1,2,3,4,5….

    2 回复  |  直到 6 年前
        1
  •  2
  •   Avin Kavish    6 年前

    但仍然不应该读取当时每个渲染的计数值。所以结果应该是

    是的,但你正在建立一个 setInterval 捕获计数器值并重复的调用 setCounter(counter + 1) 每3秒。因此,每隔3秒,计数器将重置为设置间隔加1时捕获的值。每次这样做,效果挂钩将再次启动,并设置一个新的回调每3秒重复一次。

    你是想用 setTimeout 是吗?

      useEffect(() => {
        setTimeout(() => {
          setCounter(counter+1)
        }, 3000)
      }, [counter]);
    
    // Output: 1, 2, 3, 4, 5 ....
    
        2
  •  0
  •   It worked yesterday.    6 年前

    为了了解发生了什么,我增加了一些 console.log 按规定行事。正如公认的答案所解释的

    setinterval调用,它捕获计数器的值并每3秒重复setcounter(counter+1)。

    为了解决这个问题,我在deps列表中添加了一个空数组,只注册一次setinterval,并向setcounter传递了一个回调函数来捕获当前状态值

    function App() {
    
      const [counter, setCounter] = useState(0);
    
      useEffect(() => {
        setInterval(() => {
          setCounter((storedCounter) => storedCounter+1 )
          console.log(counter, 'captured value')
        }, 3000)
      }, []);
    
      console.log(counter, ' state')
    
    
      return (
        <div>
          hi
        </div>
      );
    }
    
    export default App;
    

    enter image description here