RN 組件的生命周期如下圖: 生命周期回調函數 掛載 當組件實例被創建並插入 DOM 中時,其生命周期調用順序如下: constructor() static getDerivedStateFromProps() render() componentDidMount() 註意: 下述生命周期方法即將 ...
RN 組件的生命周期如下圖:
生命周期回調函數
掛載
當組件實例被創建並插入 DOM 中時,其生命周期調用順序如下:
註意:
下述生命周期方法即將過時,在新代碼中應該避免使用它們:
更新
當組件的 props 或 state 發生變化時會觸發更新。組件更新的生命周期調用順序如下:
static getDerivedStateFromProps()
shouldComponentUpdate()
render()
getSnapshotBeforeUpdate()
componentDidUpdate()
註意:
下述方法即將過時,在新代碼中應該避免使用它們:
卸載
當組件從 DOM 中移除時會調用如下方法:
錯誤處理
當渲染過程,生命周期,或子組件的構造函數中拋出錯誤時,會調用如下方法:
常用的生命周期方法
1、render()
render()
方法是 class 組件中唯一必須實現的方法。
當 render
被調用時,它會檢查 this.props
和 this.state
的變化並返回以下類型之一:
- React 元素。通常通過 JSX 創建。例如,
<div />
會被 React 渲染為 DOM 節點,<MyComponent />
會被 React 渲染為自定義組件,無論是<div />
還是<MyComponent />
均為 React 元素。 - 數組或 fragments。 使得 render 方法可以返回多個元素。。
- Portals。可以渲染子節點到不同的 DOM 子樹中。
- 字元串或數值類型。它們在 DOM 中會被渲染為文本節點
- 布爾類型或
null
。什麼都不渲染。(主要用於支持返回test && <Child />
的模式,其中 test 為布爾類型。)
render()
函數應該為純函數,這意味著在不修改組件 state 的情況下,每次調用時都返回相同的結果,並且它不會直接與瀏覽器交互。
如需與瀏覽器進行交互,請在 componentDidMount()
或其他生命周期方法中執行你的操作。保持 render()
為純函數,可以使組件更容易思考。
註意
如果
shouldComponentUpdate()
返回 false,則不會調用render()
。
2、constructor()
如果不初始化 state 或不進行方法綁定,則不需要為 React 組件實現構造函數。
在 React 組件掛載之前,會調用它的構造函數。在為 React.Component 子類實現構造函數時,應在其他語句之前前調用 super(props)
。否則,this.props
在構造函數中可能會出現未定義的 bug。
通常,在 React 中,構造函數僅用於以下兩種情況:
在 constructor()
函數中不要調用 setState()
方法。如果你的組件需要使用內部 state,請直接在構造函數中為 this.state
賦值初始 state。
要避免在構造函數中引入任何副作用或訂閱。如遇到此場景,請將對應的操作放置在 componentDidMount
中
3、componentDidMount()
componentDidMount()
會在組件掛載後(插入 DOM 樹中)立即調用。依賴於 DOM 節點的初始化應該放在這裡。如需通過網路請求獲取數據,此處是實例化請求的好地方。
這個方法是比較適合添加訂閱的地方。如果添加了訂閱,請不要忘記在 componentWillUnmount()
里取消訂閱
你可以在 componentDidMount()
里直接調用 setState()
。它將觸發額外渲染,但此渲染會發生在瀏覽器更新屏幕之前。如此保證了即使在 render()
兩次調用的情況下,用戶也不會看到中間狀態。請謹慎使用該模式,因為它會導致性能問題。通常,你應該在 constructor()
中初始化 state。如果你的渲染依賴於 DOM 節點的大小或位置,比如實現 modals 和 tooltips 等情況下,你可以使用此方式處理
4、componentDidUpdate()
componentDidUpdate()
會在更新後會被立即調用。首次渲染不會執行此方法。
當組件更新後,可以在此處對 DOM 進行操作。如果你對更新前後的 props 進行了比較,也可以選擇在此處進行網路請求。
componentDidUpdate(prevProps) { // 典型用法(不要忘記比較 props): if (this.props.userID !== prevProps.userID) { this.fetchData(this.props.userID); } }
你也可以在 componentDidUpdate()
中直接調用 setState()
,但請註意它必須被包裹在一個條件語句里,正如上述的例子那樣進行處理,否則會導致死迴圈。它還會導致額外的重新渲染,雖然用戶不可見,但會影響組件性能。不要將 props “鏡像”給 state,請考慮直接使用 props。
5、componentWillUnmount()
componentWillUnmount()
會在組件卸載及銷毀之前直接調用。在此方法中執行必要的清理操作,例如,清除 timer,取消網路請求或清除在 componentDidMount()
中創建的訂閱等。
componentWillUnmount()
中不應調用 setState()
,因為該組件將永遠不會重新渲染。組件實例卸載後,將永遠不會再掛載它。
不常用的生命周期方法
並不太常用。它們偶爾會很方便,但是大部分情況下組件可能都不需要它們。
1、shouldComponentUpdate()
根據 shouldComponentUpdate()
的返回值,判斷 React 組件的輸出是否受當前 state 或 props 更改的影響。預設行為是 state 每次發生變化組件都會重新渲染。
2、static getDerivedStateFromProps()
getDerivedStateFromProps
會在調用 render 方法之前調用,並且在初始掛載及後續更新時都會被調用。它應返回一個對象來更新 state,如果返回 null 則不更新任何內容。
此方法適用於 state 的值在任何時候都取決於 props。
派生狀態會導致代碼冗餘,並使組件難以維護。 確保你已熟悉這些簡單的替代方案:
- 如果你需要執行副作用(例如,數據提取或動畫)以響應 props 中的更改,請改用
componentDidUpdate
。 - 如果只想在 prop 更改時重新計算某些數據,請使用 memoization helper 代替。
- 如果你想在 prop 更改時“重置”某些 state,請考慮使組件完全受控或使用
key
使組件完全不受控 代替。
3、getSnapshotBeforeUpdate()
getSnapshotBeforeUpdate()
在最近一次渲染輸出(提交到 DOM 節點)之前調用。它使得組件能在發生更改之前從 DOM 中捕獲一些信息(例如,滾動位置)。此生命周期的任何返回值將作為參數傳遞給 componentDidUpdate()
。
此用法並不常見,但它可能出現在 UI 處理中,如需要以特殊方式處理滾動位置的聊天線程等。
應返回 snapshot 的值(或 null
)。
Error boundaries
Error boundaries 是 React 組件,它會在其子組件樹中的任何位置捕獲 JavaScript 錯誤,並記錄這些錯誤,展示降級 UI 而不是崩潰的組件樹。Error boundaries 組件會捕獲在渲染期間,在生命周期方法以及其整個樹的構造函數中發生的錯誤。
如果 class 組件定義了生命周期方法 static getDerivedStateFromError()
或 componentDidCatch()
中的任何一個(或兩者),它就成為了 Error boundaries。通過生命周期更新 state 可讓組件捕獲樹中未處理的 JavaScript 錯誤並展示降級 UI。
僅使用 Error boundaries 組件來從意外異常中恢復的情況;不要將它們用於流程式控制制。
欲瞭解更多詳細信息,請參閱 React 16 中的錯誤處理。
註意
Error boundaries 僅捕獲組件樹中以下組件中的錯誤。但它本身的錯誤無法捕獲。