昨天講到生命週期裡面的Mounting Lifecycle Methods
而今天則持續記錄下去Updating Lifecycle Methods。
1. componentWillReceiveProps(nextProps)
每次元件接收到 props 更新時被執行,通常我們會在 componentWillReceiveProps() 傳進nextProps這參數來表示即將更新的props值,在運用this.props和nextProps來比對props前後的變化,來更新元件對應的state。
但有時候不是props有更新才會呼叫,當父元件刷新子元件時也會執行componentWillReceiveProps(),因此造成可能會被執行好幾次,所以必須得避免有任何 side effect 的 code 寫在裡面。
元件第一次 render() 時,React 不會 call componentWillReceiveProps()。
由於 componentWillReceiveProps 容易被誤解誤用,從 React 17 開始被拿掉。因此要 props 變化更新 state 請改用 getDerivedStateFromProps;如果是要聽props變化來做一些side effect操作請改用 componentDidUpdate。
2. shouldComponentUpdate(nextProps, nextState)
大多在想'最佳化效能(performance)'時使用,每當props 或 state 有更新React會在call render()重繪畫面前,先行呼叫shouldComponentUpdate()來決定是否真的需要進行render()。
雖然React會自動偵測props 和 state的改變來自動更新元件(re-render),但有些狀況就可以使用此方法來幫助React更精準判斷元件是否真的需要更新。作法很簡單可以針對新舊props和state來判斷,當執行後必須返回一個布林值(Boolean)來告訴React是否更新元件,返回false時,'componentWillUpdate()', 'render()', 'componentDidUpdate()'這些 'Lifecycole Methods' 就不會被執行。
範例如下:
shouldComponentUpdate(nextProps, nextState) {
console.log('nextState: ', nextState);
if (nextState.counter > 3) return false; // => 超過 3 就不要 call render()
return true;
}
若沒有呼叫則預設值就會返回true
3. componentWillUpdate(nextProps, nextState)
在 shouldComponentUpdate 和 render 之間被呼叫到。適合用在和 React 無關的設定,像是檢查 window 的尺寸。因為他可能在整個運作過程中會被執行好幾次,所以一定得'避免有任何side effect的code'在裡面,同時在'componentWillUpdate()'中也禁止任何更新到元件的動作,像是call this.setState(),如果有需要更新State 請用 'getDerivedStateFromProps'。
由於 componentWillUpdate 容易被誤解誤用,從 React 17 開始被拿掉。
4. static getDerivedStateFromProps(props, state)
getDerivedStateFromProps() 是一個 static method,會在「每一次」跑 render() 之前被呼叫執行。執行時會傳入當前的 props 和 state,執行後需要返回一個物件 (object) 來表示欲更新的 state 或返回 null 表示不更新。
此方法只是為了一些少數狀況而存在,基本上都有很多其他替代方案,因此不建議使用
5. render()
是React Component一定要實作的方法,每次props或state被改變時,都會被執行一次。在render()中我們會依據當前this.props及this.state資料狀態,來決定元件當前的UI結構與顯示內容。但實作上通常會保持render()是一個pure function,不會更改State值,也不在裡面寫任何造成side-effects的code
render() 可以返回下面這幾種資料型態其一:
* React elements通常 render() 返回的就是用 JSX 建立的 React 元素。
* String / numbers可以返回字串或是數字,這會被當作是 HTML DOM 的 text nodes 來顯示。
* null返回 null 告訴 React 不顯示任何東西。
* Booleans返回布林值 false 也是告訴 React 不顯示任何東西
6. getSnapshotBeforeUpdate(prevProps, prevState)
在畫面實際渲染 (rendered) 前一刻被呼叫執行,簡單的說觸發的時機點是在 React 進行修改前,通常是更新 DOM 前。當被執行後 return 的值會被傳進 componentDidUpdate 的第三個參數。
class ScrollingList extends React.Component {
getSnapshotBeforeUpdate(prevProps, prevState) {
// 如果 list 內容有變動,有新東西加到 list 前面時
if (prevProps.list.length < this.props.list.length) {
const list = this.listRef.current;
// 紀錄更新前一刻,捲軸的位置 scroll position
return list.scrollHeight - list.scrollTop;
}
return null;
}
}
getSnapshotBeforeUpdate 是從 React 16.3 提供的新方法。
7. componentDidUpdate(prevProps, prevState, snapshot)
會在元件更新完成、執行完 render() 重繪後被執行。而每一次元件更新時,React 確保 componentDidUpdate() 只會被執行一次。而這邊可以執行比對 prevProps/prevState 及 this.props/this.state 狀態差異,做像是存取 DOM、重畫 Canvas、重整頁面 layout、AJAX 網路呼叫等動作。如果 component 有實作 'getSnapshotBeforeUpdate' 方法那'getSnapshotBeforeUpdate'它的返回值 (return value) 會被傳進去,而'componentDidUpdate'當作第三個參數'snapshot',沒實作的話這參數值就會是 undefined。
componentDidUpdate(prevProps, prevState, snapshot) {
// 如果有 snapshot
if (snapshot !== null) {
const list = this.listRef.current;
// 調整 scroll 的位置,避免畫面才不會被新的東西推開
list.scrollTop = list.scrollHeight - snapshot;
}
}
元件第一次 render() 時,React 不會 call componentDidUpdate()。