[ReactDoc] React Hooks - useEffect
本文章內容來自:
- Using the Effect Hook @ React Docs
- A Complete Guide to useEffect @ Overreacted
- You Might Not Need an Effect @ React Docs Beta
useEffect 的使用時機類似在傳統 class 中使用 componentDidMount, componentDidUpdate 和 componentWillUnmount 的生命週期,關於 useEffect 的基本說明可以參考「React Hooks 起步走」。
在 Dan Abramov 的 A Complete Guide to useEffect 中提到,在學習 useEffect 時,我們應該忘記過去對於 React 生命週期所學到的,以全新的體驗和思考方式來認識 useEffect。
筆記
- 使用
useEffect一定要留意第一次執行的時間點,如果第一次不想要執行 要 return 掉 - 使用
useEffect一定要留意 dependencies 陣列中的變數,它們的改變會觸使 useEffect 執行 - dependencies array 是透過 Object.is() 來比較兩個值是否相等
// 第一次資料進來時 state 可能是 undefined(例如 AJAX),此時不要執行
useEffect(() => {
if (hasScreenPermission === undefined) return;
// 第二次拿到 state 後才執行...
setState({
error: 'foobar',
});
}, [hasScreenPermission, setState]);
留意重點
- 簡單來說,
useEffect內的 effect 會在每一次 DOM 轉譯後被呼叫(不論是 mounted 或 updated);如果有回傳 cleanup function 的話,則會在每一次 DOM 轉譯後的最開始先被呼叫,接著才執行該次的 effect(元件 unmount 或每次 updated 前被呼叫)。 - 實際上在每一次元件轉譯時
useEffect內的函式都是新的、不同的,並會把舊的給覆蓋;換句話說,effect 會更像是隸屬於每次轉譯的一部分。 - 由於這些 effects 會在每次元件轉譯時都執行(而非只執行一次),因此實際上
useEffect中回傳的 cleanup 函式並非只有在元件 unmount 時被呼叫到,而是在每次執行該 effect 前也會呼叫一次 clean up 的函式。 - 和
useState一樣,在一個元件中可以多次使用useEffect,因此你可以根據程式邏輯拆成許多不同的 effects。
Hooks 基本使用
在 React 元件中有兩種常見的副作用(side effects),一種需要被清理(cleanup),一種則不用。
不需要被清理的作用(Effects Without Cleanup)
有時我們會需要在 React 更新完 DOM 之後來執行其他的程式碼,像是網路請求(Network request)、手動操作 DOM(manual DOM mutation)或紀錄(logging),這些都是常見不需要被清理的作用,也就是做完就不用再去管它。
透過使用 useEffect 這個 Hook,你將可以在元件轉譯完成後去做一些事,React 會記得你傳入 useEffect 內的 function(這個 function 我們稱做 effect),並在執行完 DOM 的更新後呼叫它。
預設的情況下這些 effect 會在元件第一次被轉譯以及後續每一次更新時被呼叫到(除非去自訂這樣的行為),因此,現在不必再去想這個方法需要在 mounting 還是 updating 時被呼叫,只要知道這些 effect 會在元件「轉譯後(after render)」被呼叫,React 會確保 DOM 已經更新完成後才去呼叫這個 effect。
和 componentDidMount 或 componentDidUpdate 不同的地方在於,在 useEffect 中的 effects 並不會使得瀏覽器阻塞而無法更新畫面,大部分的 effects 並不需要同步(synchronously)處理,少部分除了像是要測量 layout 這種 effect,則會使用 useLayoutEffect Hook。