iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 10
4
Modern Web

在 React 生態圈內打滾的一年 feat. TypeScript系列 第 10

Day09 | 掌管 Lifecycle 和一切作用的 useEffect

  • 分享至 

  • xImage
  •  

前言

Lifecycle 被稱為生命週期,在 Component 中,我們可以大致把生命週期分成三個:

  1. Component Render 完畢。
  2. Component 內的 State 改變。
  3. Component 被移除時。

所以 Lifecycle 可以是一個 Component 的生老病死,文中會來學習如何控制每個階段應該要發生的事情。


前置準備

  1. 文中的專案會以 Day08 的專案架構繼續講解,如果未跟到前一天的進度,可以從 GitHub 上 Clone 下來。
  2. 一顆擁有學習熱忱的心。

使用方法

useEffect

useEffect 是掌管 Function Component 生命週期的 Hooks,此 Hooks 會接收一個 function,在特定情況的時候執行它,基本用法如下:

從 React 中 import:

import React, { useEffect } from 'react';

使用方式:

useEffect(() => {
  // Do something...
});

特定情況

前言有提到,Lifecycle 在 Component 中可以分為三個時間點,接下來會一一講解在不同情況下如何設置 useEffect

Component Render 完時

當 Component Render 後,我們期望能夠從 API 中獲取資料,但只需在開始時執行一次,今後不論是 State 改變或是 Component 被移除時,都不再調用,那就得在使用 useEffect 時,將空陣列 [] 送入第二個參數:

useEffect(() => {
  // Do something...
}, []);

下方開啟 src/index.jsx,並在 Main Component 中輸入上方程式,讓它在執行時打印一些訊息在 console 中:

Component Render 後便會直接執行一次:

Component 內的 State 更新時

State 更新的生命週期得用到 useEffect 的第二個參數,就是上方傳入空陣列的那個位置,我們可以藉由指定 State 名稱,使它作為該 State 改變時會調用的 function:

// 在第二個參數陣列中傳入 State 名稱
useEffect(() => { }, [count]);

注意哦!第二個陣列的部分也可以不給,但這樣會造成 Component 內任一的 State 改變時都會執行!

然後這個部分比較特別,在 State 改變時,還可以切成兩個時間點,分別為「 State 更新前」和「 State 更新後」兩種。

State 更新後需觸發事件的寫法其實就和第一個生命週期相同,只要在 useEffect 的第二個參數中指定了某個 State,就能執行第一個參數 function 的內容:

上方設置的 useEffect 會於 Component Render 完畢及 State 每次更新後執行:

接著,有時候在 State 改變前的值也是有用處的,我們可以把要執行的內容放置於 useEffect 第一個參數 function 的回傳值中,例如:

執行結果如下,可以發現 useEffect 總是會先執行 return 中的內容,再執行 function ,且 State 的值也正好是改變前和後的:

Component 被移除時

最後一個生命週期就像 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 中的 componentDidMountcomponentDidUpdatecomponentWillUnmount,藉由對 useEffect 不同的設置,便產生不同的效果,且還能區隔各個 State 改變後的執行事件,不會使所有的事情都放在一起處理,讓程式碼更易讀,職責也相對分明。

如果文章中有任何問題,或是不理解的地方,都可以留言告訴我!謝謝大家!


上一篇
Day08 | Function Component 的 State 在哪裡
下一篇
Day10 | Props 太多, Component 就容易出錯, 就讓 Prop-Types 替你把關吧!
系列文
在 React 生態圈內打滾的一年 feat. TypeScript31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中
0
richardwang4314
iT邦新手 5 級 ‧ 2020-01-15 16:28:32

最後一張圖的改變前改變後是不是相反了?

對,我也這麼認為,因為useEffect裡面的return會先被執行。

神Q超人 iT邦研究生 5 級 ‧ 2021-04-23 22:22:58 檢舉

對抱歉 XD,藏在圖片裡面的小 Bug,我來勘誤一下!非常感謝!

1
matuyou0301
iT邦新手 5 級 ‧ 2021-04-15 10:59:35

useEffect的return居然會先被執行,其實有點小大開眼界,因為一般在撰寫JS的時候return都是作為結果在回傳的感覺,不過React想法果然不一樣,看來須有一個React小腦 :D。

省去撰寫componentDitMount, WillMount這些真的是一大救星......

0
連城
iT邦新手 4 級 ‧ 2021-08-07 18:08:08

溫故而知新
我又回頭重新練一次了
這次好像又有地方變了

useEffect(() => {
    console.log (`render後執行`);
  });
//console.log內容現在要用``才能顯示出來

我要留言

立即登入留言