React16.8新增的useEffec這個hook函數就是處理副作用的。
所謂的“副作用”,舉個通俗一點的例子,假如感冒了本來吃點藥就沒事了,但是吃了藥發現身體過敏了,而這個“過敏”就是副作用。
放到React中,本來只是想渲染DOM展示到頁面上,但除了DOM之外還有數據,而這些數據必須從外部的數據源中獲取,這個“獲取外部數據源”的過程就是副作用。
useEffect怎么用可以參考官網給出的例子,這里主要針對使用useEffect過程中遇到的問題進行總結。
避免重復循環渲染
利用useEffect接收一個數組作為第二個參數,將第二個參數作為dependence,每次渲染完DOM執行副作用函數時都會淺比較dependence渲染前后的值是否一致,不一致就執行副作用,反之就不執行;如果該dependence為一個空數組[],即沒有傳入比較變化的變量,則比較結果永遠都保持不變,那么副作用邏輯就只能執行一次。
1
2
3
4
5
|
useEffect(() => { setTimeout(() => { setCounter(counter + 1); }, 300) }, []); |
初此之外,如果我們還想通過點擊刷新按鈕實現獲取外部數據但又不想造成死循環,那么可以通過一個變量作為“開關”,在實現目的的同時做到避免循環渲染DOM。
畫動圖太麻煩,各位看注釋腦補
1
2
3
4
5
6
7
8
9
|
function App() { const [count, setCount] = useState(0); const [loading, setLoading] = useState( true ); // loading作為開關 useEffect(() => { if (loading) { // 注意這里只有當loading為true時才執行 setTimeout(() => { setCount(count + 1); setLoading(!loading); // 改變loading值 }); } }, [loading]); // loading在這里作為dependence // 第一次DOM渲染完成后,loading為true,執行副作用函數,count值變為1,loading變為false,由于 // 改變了state的值,會update,組件會再次render,但此時loading為false,不會執行setTimeout, // 避免了循環 // 當點擊Refresh刷新,loading由上一次的false變為了true,函數執行一次update // DOM更新完后執行useEffect,因為loading已經為true了,所以副作用函數可執行,count從1變為2, // loading又從true變為false,就這樣交替進行。。。 return ( <div> <h3>{count}</h3> <button onClick={() => { setLoading( true ); }} > Refresh </button> </div> );} |
關于副作用的清除
useEffect可以返回一個函數來作為清除副作用。
1
2
3
4
5
6
7
|
useEffect(() => { ChatAPI.subscribeToFriendStatus(props.id, handleStatusChange); function clear(){ ChatAPI.unsubscribeFromFriendStatus(props.id, handleStatusChange); } return clear; }); |
這里會涉及到useEffect執行和銷毀的過程:
- 傳入props.id = 1
- 組件渲染
- DOM渲染完成,執行副作用函數,返回清除副作用函數clear,命名為clear1
- 傳入props.id=2
- 組件渲染
- DOM渲染完成,執行clear1
- 副作用函數執行并返回另一個clear函數,命名為clear2
- 組件銷毀,clear2執行
由此可推測出副作用清除函數的特征:
- 每次副作用執行都會返回一個清除函數
- 清除函數會在下一次副作用函數執行之前(DOM渲染完成之后)執行
- 組件銷毀也會執行一次清除函數
從打印出的count值也可以看出,清除函數會在下一次副作用函數執行之前執行,即在清除函數里的count值是上一次緩存的count值:
進一步思考,clear1執行的時候,訪問了props.id,那么這個id值是1還是2呢?
這里就涉及到閉包的知識概念了,因為useEffect返回的是個函數,在執行時產生了一個閉包,根據閉包的相關定義,返回的clear函數能訪問自身作用域外的變量,當組件第一次渲染時傳入id=1,此時的clear函數中的props.id值為1。
以上就是React useEffect的理解與使用的詳細內容,更多關于React useEffect的資料請關注服務器之家其它相關文章!
原文鏈接:https://juejin.cn/post/6952436447144050725