Lifecycle 被稱為生命週期,在 Component 中,我們可以大致把生命週期分成三個:
useEffect
是掌管 Function Component 生命週期的 Hooks,此 Hooks 會接收一個 function,在特定情況的時候執行它,基本用法如下:
從 React 中 import:
import React, { useEffect } from 'react';
使用方式:
useEffect(() => {
// Do something...
});
前言有提到,Lifecycle 在 Component 中可以分為三個時間點,接下來會一一講解在不同情況下如何設置 useEffect
。
當 Component Render 後,我們期望能夠從 API 中獲取資料,但只需在開始時執行一次,今後不論是 State 改變或是 Component 被移除時,都不再調用,那就得在使用 useEffect
時,將空陣列 []
送入第二個參數:
useEffect(() => {
// Do something...
}, []);
下方開啟 src/index.jsx,並在 Main
Component 中輸入上方程式,讓它在執行時打印一些訊息在 console
中:
Component Render 後便會直接執行一次:
State 更新的生命週期得用到 useEffect
的第二個參數,就是上方傳入空陣列的那個位置,我們可以藉由指定 State 名稱,使它作為該 State 改變時會調用的 function:
// 在第二個參數陣列中傳入 State 名稱
useEffect(() => { }, [count]);
然後這個部分比較特別,在 State 改變時,還可以切成兩個時間點,分別為「 State 更新前」和「 State 更新後」兩種。
State 更新後需觸發事件的寫法其實就和第一個生命週期相同,只要在 useEffect
的第二個參數中指定了某個 State,就能執行第一個參數 function 的內容:
上方設置的 useEffect
會於 Component Render 完畢及 State 每次更新後執行:
接著,有時候在 State 改變前的值也是有用處的,我們可以把要執行的內容放置於 useEffect
第一個參數 function 的回傳值中,例如:
執行結果如下,可以發現 useEffect
總是會先執行 return
中的內容,再執行 function ,且 State
的值也正好是改變前和後的:
最後一個生命週期就像 State
改變前的操作,只是不需要在 useEffect
第二個參數陣列中指定 State
,如同 Component Render 後,直接給一個空陣列就可以了。
下方的範例為了實現 Component 被移除的過程,我將計數器的部分拆成另一個 Component ,並用 useEffect
對它設定移除時執行的生命週期:
上方程式碼內的錯誤為 ESLint 檢查的錯誤,為了讓大家更容易理解就維持原狀。
抽出 Counter
後,另外使用 Main
控制它的 Render :
如此一來,當我點擊按鈕將 Counter
移除時,Counter
內的 useEffect
就會執行:
最後和大家說明,一個 Component 內是可以有多個 useEffect
的,這麼做可以讓我們區隔每個 useEffect
它應該要做的事:
勘誤一下,上方圖片中,在 useEffect 的 return 裡面的 console.log,應該是「state 改變之前」而 callback 函式內的應該是「state 改變之後」
本文的原始碼內容會放置於 GitHub 上,歡迎各位參考使用。
useEffect
取代了原本 Class Component 中的 componentDidMount
、componentDidUpdate
、componentWillUnmount
,藉由對 useEffect
不同的設置,便產生不同的效果,且還能區隔各個 State 改變後的執行事件,不會使所有的事情都放在一起處理,讓程式碼更易讀,職責也相對分明。
如果文章中有任何問題,或是不理解的地方,都可以留言告訴我!謝謝大家!
最後一張圖的改變前
跟改變後
是不是相反了?
對,我也這麼認為,因為useEffect裡面的return會先被執行。
對抱歉 XD,藏在圖片裡面的小 Bug,我來勘誤一下!非常感謝!
useEffect的return居然會先被執行,其實有點小大開眼界,因為一般在撰寫JS的時候return都是作為結果在回傳的感覺,不過React想法果然不一樣,看來須有一個React小腦 :D。
省去撰寫componentDitMount, WillMount這些真的是一大救星......
溫故而知新
我又回頭重新練一次了
這次好像又有地方變了
useEffect(() => {
console.log (`render後執行`);
});
//console.log內容現在要用``才能顯示出來