在 useEffect 中调用 setInterval 时会发生什么

What happens when setInterval is called within a useEffect

我有以下反应组件。

function App() {

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

  useEffect(() => {
    setInterval(() => {
      setCounter(counter+1)
    }, 3000)
  }, [counter]);

  console.log(counter)

  
  return (
    <div>
      hi
    </div>
  );
}

export default App;

我得到了这样的结果

0

1

1

2

1

2

3 ...

我确实了解,每次调用 setCounter 都会重新渲染组件,并且每次渲染都会重新创建 useEffect 回调。我的问题是不应该通过 resulting

读取当时每个渲染的计数值

1, 2, 3, 4, 5 ....

But still should not that read the count value of the each render at the time. So the result should be

是的,但您正在设置一个 setInterval 调用,该调用捕获计数器的值并每 3 秒重复一次 setCounter(counter + 1)。因此,每 3 秒计数器将重置为设置间隔时捕获的值加一。每次执行时,效果挂钩都会再次触发并设置一个新的回调,每 3 秒重复一次。

您是要使用 setTimeout 吗?

  useEffect(() => {
    setTimeout(() => {
      setCounter(counter+1)
    }, 3000)
  }, [counter]);

// Output: 1, 2, 3, 4, 5 ....

为了了解发生了什么,我在代码中添加了一些 console.log。正如接受的答案所解释的那样

setInterval call that captures that value of counter and repeats setCounter(counter + 1) every 3 seconds.

为了解决这个问题,我在 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;