React 的 16.3 版本中對生命週期進行了較大的調整,這是為了開發者能正確地使用生命週期,避免誤解其概念而造成反模式。
本文將重點介紹 getDerivedStateFromProps 這個生命週期。要注意的是,React 16.3 的版本中 getDerivedStateFromProps 的觸發範圍是和 16.4^ 是不同的,主要區別是在 setState
和 forceUpdate
時會不會觸發,具體可以看這個生命全週期圖 。
用法
getDerivedStateFromProps exists for only one purpose. It enables a component to update its internal state as the result of changes in props.
從上邊這句話中,我們可以清晰知道 getDerivedStateFromProps 的作用就是為了讓 props 能更新到元件內部 state 中。所以它可能的使用場景有兩個:
- 無條件的根據 prop 來更新內部 state,也就是隻要有傳入 prop 值, 就更新 state
- 只有 prop 值和 state 值不同時才更新 state 值。
我們接下來看幾個例子。
假設我們有個一個表格元件,它會根據傳入的列表資料來更新檢視。
class Table extends React.Component {
state = {
list: []
}
static getDerivedStateFromProps (props, state) {
return {
list: props.list
}
}
render () {
.... // 展示 list
}
}
複製程式碼
上面的例子就是第一種使用場景,但是無條件從 prop 中更新 state,我們完全沒必要使用這個生命週期,直接對 prop 值進行操作就好了,無需用 state 值類儲存。
在看一個例子,這個例子是一個顏色選擇器,這個元件能選擇相應的顏色並顯示,同時它能根據傳入 prop 值顯示顏色。
Class ColorPicker extends React.Component {
state = {
color: '#000000'
}
static getDerivedStateFromProps (props, state) {
if (props.color !== state.color) {
return {
color: props.color
}
}
return null
}
... // 選擇顏色方法
render () {
.... // 顯示顏色和選擇顏色操作
}
}
複製程式碼
現在我們可以這個顏色選擇器來選擇顏色,同時我們能傳入一個顏色值並顯示。但是這個元件有一個 bug,如果我們傳入一個顏色值後,再使用元件內部的選擇顏色方法,我們會發現顏色不會變化,一直是傳入的顏色值。
這是使用這個生命週期的一個常見 bug。為什麼會發生這個 bug 呢?在開頭有說到,在 React 16.4^ 的版本中 setState
和 forceUpdate
也會觸發這個生命週期,所以內部 state 變化後,又會走 getDerivedStateFromProps 方法,並把 state 值更新為傳入的 prop。
接下里我們來修復這個bug。
Class ColorPicker extends React.Component {
state = {
color: '#000000',
prevPropColor: ''
}
static getDerivedStateFromProps (props, state) {
if (props.color !== state.prevPropColor) {
return {
color: props.color
prevPropColor: props.color
}
}
return null
}
... // 選擇顏色方法
render () {
.... // 顯示顏色和選擇顏色操作
}
}
複製程式碼
通過儲存一個之前 prop 值,我們就可以在只有 prop 變化時才去修改 state。這樣就解決上述的問題。
這裡小結下 getDerivedStateFromProps 方法使用的注意點:
- 在使用此生命週期時,要注意把傳入的 prop 值和之前傳入的 prop 進行比較。
- 因為這個生命週期是靜態方法,同時要保持它是純函式,不要產生副作用。
上述的情況在大多數情況下都是適用,但是這邊還是會有產生 bug 的風險。具體可以官網提供這個例子。在 One 和 Two 的預設賬號都相同的情況下,使用同一個輸入框元件,在切換到 Two,並不會顯示成 Two 的預設賬號。
這邊解決方法有四種:
第一種是將元件改成完全可控元件(也是狀態值和方法全由父類控制);
第二種是改成完全不可控元件(也就是元件不接受在 getDerivedStateFromProps 中通過 prop 值來改變內部狀態),然後通過設定在建構函式中把 prop 傳給 state 和設定 key 值來處理,因為 key 變化的時候 React 會重新渲染元件,而不是去更新元件。
第三種還是保持上述元件模式,然後通過一個唯一 ID 來判斷是否更新,而不是通過 color 值來判斷。
第四種不使用 getDerivedStateFromProps,通過 ref 來把改變郵箱的方法暴露出去。
反模式
常見的反模式有兩種,上邊也有提到過。
- 無條件地根據 prop 值來更新 state 值
- 當 prop 值變化並且和 state 不一樣時就更新 state (會造成內部變化無效,上述也提到過)。
總結
我們應該謹慎地使用 getDerivedStateFromProps 這個生命週期。我個人使用情況來說,使用時要注意下面幾點:
- 因為這個生命週期是靜態方法,同時要保持它是純函式,不要產生副作用。
- 在使用此生命週期時,要注意把傳入的 prop 值和之前傳入的 prop 進行比較(這個 prop 值最好有唯一性,或者使用一個唯一性的 prop 值來專門比較)。
- 不使用 getDerivedStateFromProps,可以改成元件保持完全不可控模式,通過初始值和 key 值來實現 prop 改變 state 的情景。
更多詳細內容可以閱讀官網 Blog。