React在定時器中無法獲取狀態最新值的問題

在定時器中無法獲取狀態最新值

在做輪播圖組件時發現瞭一個問題,在setInterval中無法通過狀態直接獲取最新值,如:

const [rightTransform, setRightTransform] = useState(pictureSize);

const autoPlay = () => {        //普通輪播自動播放
    timer.current = setInterval(() => {
      let oldState = rightTransform;
      console.log('老狀態', oldState)			//始終隻會打印初始的pictureSize
      setRightTransform(o => {
        const newState = JSON.parse(JSON.stringify(o));
        return newState >= (renderImgList.length) * pictureSize ? 0 : newState + pictureSize
      })
	}, 1000);
}

問題原因

定時器一直都沒有被清除,因此獲取的狀態始終是定時器被創建時候的狀態。

問題解決

從代碼和圖片可以看到,定時器中打印的狀態永遠都是初始值,後面所改變的值雖然更新瞭,頁面也發生瞭變化,但是我們從log中無法獲取到實時狀態。

解決辦法很簡單:

第一種,就是在setState中獲取上一次狀態,因為useState hooks提供瞭記錄上一次狀態的緩存回調,可以在這個回調中獲取上一輪狀態

如圖:

timer.current = setInterval(() => {
      let oldState = rightTransform;
      setRightTransform(o => {
        console.log('在setState中的老狀態', o)
        const newState = JSON.parse(JSON.stringify(o));
        return newState >= (renderImgList.length) * pictureSize ? 0 : newState + pictureSize
      })
      console.log('直接打印老狀態', oldState)
}

ReactHook hooks和定時器產生的bug

問題1

使用定時器改變state,state的值並不是最新值

例:

 const _onClick = function ()
 {
   setInterval(() => {
     console.log(value);
     setValue(value + 1);
   },1000)
 }

產生原因:因為每次setValue後會重新創建函數,由於並沒有及時清理掉setInterval,setInterval執行的上下文環境都是第一次創建本函數式組件的上下文(所以value值不會超過1)

解決方案        

方案一:

setInterval(() => {
     console.log(value);
     setValue(v=>v+1);      函數式的setValue會保存上一次的值,所以會取得最新值,該方式指定state該如何改變而不用引用當前state
   },1000)

    

方案二:

useEffect(() => {
     const id = setInterval(() => {
         valf.current++;    不一定是ref操作,正常set操作即可
       }, 1000);
       return () => clearInterval(id);
   }, []);

以上為個人經驗,希望能給大傢一個參考,也希望大傢多多支持WalkonNet。 

推薦閱讀: