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。
推薦閱讀:
- React中父子組件通信詳解
- React hooks useState異步問題及解決
- React 狀態的不變性實例詳解
- React 小技巧教你如何擺脫hooks依賴煩惱
- 基於React Hooks的小型狀態管理詳解