簡體   English   中英

React hooks:新狀態值未反映在 setInterval 回調中

[英]React hooks: new state value not reflecting in setInterval callback

我有一個函數反應組件,它有一個從 10000 開始並變為 0 的計數器。

我在組件安裝期間使用 useEffect 鈎子設置 setInterval 回調。 然后回調更新計數器狀態。

但我不知道為什么, count數值永遠不會減少。 每次回調運行count為 10000。

(我正在使用 react 和 react-dom 版本16.8.3

功能組件如下:

import React, { useState, useEffect, useRef } from 'react'

const Counter = () => {
  const timerID = useRef()
  let [count, setCount] = useState(10000)

  useEffect(() => {
    timerID.current = setInterval(() => {
      //count here is always 10000
      if (count - 1 < 0) {
        setCount(0)
      } else {
        setCount(count - 1)
      }
    }, 1)
  }, [])

  return <h1 className="counter">{count}</h1>
}

export default Counter

這是codeandbox的鏈接: link

您需要注意count變化,並清理您的useEffect()

useEffect(() => {
    timerID.current = setInterval(() => {
      if (count - 1 < 0) {
        setCount(0)
      } else {
        setCount(count - 1)
      }
    }, 100)

    return () => clearInterval(timerID.current);
  }, [count])

正如@Pavel 所提到的,Dan Abramov 在這里解釋了原因。

有2個選項:

1) 在依賴項中包含count

這並不理想,因為這意味着每次更改count都會創建一個新的setInterval ,因此您需要在每次渲染時清理它,例如:

  useEffect(() => {
    timerID.current = setInterval(() => {
      //count here is always 10000
      if (count - 1 < 0) {
        setCount(0)
      } else {
        setCount(count - 1)
      }
    }, 1)
    return () => clearInterval(timerID.current) // Added this line
  }, [count]) // Added count here

2)在setInterval回調函數中添加count

這是間隔的最佳方法,因為它避免了一直設置新的間隔。

 useEffect(() => {
    timerID.current = setInterval(() => {
      // count is used inside the setCount callback and has latest value
      setCount(count => {
        if (count - 1 < 0) { // Logic moved inside the function, so no dependencies
          if (timerID.current) clearInterval(timerID.current)
          return 0
        }
        return count - 1
      })
    }, 1)
    return () => {
      if (timerID.current) clearInterval(timerID.current) // Makes sure that the interval is cleared on change or unmount
    }
  }, [])

這是沙箱鏈接

如您所說,您在組件安裝時聲明了效果功能。 所以在那個時間值存儲的范圍內,count 等於 10000。這意味着每次執行時間間隔函數都會從閉包 (10000) 中獲取計數值。 正確地做到這一點實際上非常困難。 丹寫了整篇關於它的博客文章

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM