昨天對 class-based component 有了初步的認識,然而除了 state ,在 hooks 出來以前 class component 還有一項 functional component 做不到的特性 - Lifecycle
昨天的範例中仔細觀察可以發現 class-based component 中的 return statement 是被包在 render 的函式內的,其實在 class-based component 中是有提供幾個內建的函式的,而每個函式代表著 component 的某個階段(也可以看成時間點),組在一起就成了所謂的 Lifecycle,這項特性讓身為開發者的我們可以掌控一個 component 的生命週期,從元件準備被渲染到頁面、狀態更新後重新渲染、準備從頁面上移除前...等,我們可以在那些時間點做些我們希望做的事,使我們對元件的掌握度更高。
從上面這張圖可以看出 React component 生命週期的樣子。大致上可以分為:Mounting、Updateing、Unmounting 三個階段,各個階段又有不同的 function 可以使用。
而我挑幾個比較重要的介紹:
es6 的 class 語法糖,初始化並建構物件,可以用來綁定 method,但可以透過 arrow function 綁定 method ,因此也不一定需要用到 constructor,最一開始時 state 物件需要寫在 constructor 中,但現在 state 已經可以放在 constructor 外(像是昨天的範例),因此使用到 constructor 的時機就更少了,基本上自己在寫的時候已經不呔會用到它了。
render 函式負責把你寫在 return statement 後的 JSX 渲染到頁面上,而前面也有講過,在 class-based component 中,調用 setState 函式或是更新父元件傳下去的 props 都會造成重新渲染(re-render),重新渲染指的其實就是再跑一次 render function。
render 函式執行完後就會調用 componentDidMount,這也是我認為使用最多的生命週期(render除外),如 ajax API 串接或綁定 DOM 事件都會在這個函式中執行。順帶提醒一下,若是在這裏綁定了 DOM eventListener,記得在 unmounting 階段移除監聽,否則若重新渲染則 componentDidMount 將再次被觸發,造成過多的綁定事件。
componentDidMount() {
// 模擬 ajax 請求
fetch('some url')
.then((res) => res.json())
.then((data) => console.log(data))
}
顧名思義就是在狀態更新且重新渲染後被觸發的函式。在這可以處理call api動作,或是setState,促使重新 update ,但提醒記得要判斷執行時機,否則會進入無限迴圈。
componentDidUpdate(prevProps) {
if (this.props.name !== prevProps.name) {
updateUser(this.props.id);
}
}
component 要被移除的時候會執行此函式,可以做清除綁定 eventlistener,或清除 cookie、local storage等機制,另外需要注意的事,在這裏執行 setState 是不會觸發 re-render 的。
介紹了上面的幾個 function ,可以歸納出他們的觸發順序應為
constructor -> render -> componentDidMount -> render(re-render by updating) -> componentDidUpdate -> componentWillUnmount
而我們現在可以透過這些生命週期函式對元件做更全面的管理與效能優化,functional component 並沒有這些函式可以使用,但是我們可以透過 hooks 達到類似生命週期的控制。這也是我選擇先介紹 class-based component lifecycle 的原因,在了解概念後,再去學習 hooks ,更可以了解 hooks 的到來帶來了哪些好處,明天將介紹第二個 hook - useEffect,來達到類似 lifecycle 的功能。
明天見,祝大家中秋節快樂~