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內容現在要用``才能顯示出來