10秒鐘理解react生命周期
- 2019 年 10 月 3 日
- 筆記
慎點!這是一篇很水很水的文章, 抄自react中文文檔, 本文詳細介紹了react生命周期函數執行順序, 以及各生命周期函數的含義和具體作用.
不同階段生命周期函數執行順序
掛載(Mounting)
掛載指的是組件被實例化並插入到dom中
順序如下:
constructor -> getDerivedStateFromProps -> render -> componentDidMount
更新(Updating)
當state變化或者props變化會引起更新
順序如下:
getDerivedStateFromProps -> shouldComponentUpdate -> render -> getSnapshotBeforeUpdate -> componentDidUpdate
卸載
指的是組件被從dom移除
只會執行一個生命周期:
componentWillUnmount
總結
這張圖形象表示了不同階段生命周期函數執行順序.
各生命周期函數介紹
常用的生命周期
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 的情況下,每次調用時都返回相同的結果,並且它不會直接與瀏覽器交互。
注意
如果 shouldComponentUpdate() 返回 false,則不會調用 render()。
constructor()
在 React 組件掛載之前,會調用它的構造函數。
通常,在 React 中,在構造函數中只做兩件事:
- 通過給 this.state 賦值對象來初始化內部 state。
- 為事件處理函數綁定實例
注意:
- 在為 React.Component 子類實現構造函數時,應在其他語句之前前調用 super(props)。否則,this.props 在構造函數中可能會出現未定義的 bug。
- 不要在裡邊調用setState
componentDidMount()
componentDidMount() 會在組件掛載後(插入 DOM 樹中)立即調用。
在這裡可以
- setState
- 操作dom
- 發請求獲取初始數據
注意
你可以在 componentDidMount() 里可以直接調用 setState()。它將觸發額外渲染,但此渲染會發生在瀏覽器更新螢幕之前。如此保證了即使在 render() 兩次調用的情況下,用戶也不會看到中間狀態。請謹慎使用該模式,因為它會導致性能問題。通常,你應該在 constructor() 中初始化 state。如果你的渲染依賴於 DOM 節點的大小或位置,比如實現 modals 和 tooltips 等情況下,你可以使用此方式處理.
componentDidUpdate(prevProps, prevState, snapshot)
componentDidUpdate() 會在更新(dom已經更新)後會被立即調用。首次渲染不會執行此方法。
當組件更新後,可以在此處對 DOM 進行操作。如果你對更新前後的 props 進行了比較,也可以選擇在此處進行網路請求。(例如,當 props 未發生變化時,則不會執行網路請求)。
你也可以在 componentDidUpdate() 中直接調用 setState(),但請注意它必須被包裹在一個條件語件里,正如上述的例子那樣進行處理,否則會導致死循環。它還會導致額外的重新渲染,雖然用戶不可見,但會影響組件性能。不要將 props 「鏡像」給 state,請考慮直接使用 props。
如果組件實現了 getSnapshotBeforeUpdate() 生命周期(不常用),則它的返回值將作為 componentDidUpdate() 的第三個參數 「snapshot」 參數傳遞。否則此參數將為 undefined。
componentWillUnmount()
componentWillUnmount() 會在組件卸載及銷毀之前直接調用。
在這裡可以釋放資源, 比如清除定時器, removeEventListener
注意
這裡邊setState是無效的, 不應該調用
不常用的生命周期
shouldComponentUpdate(nextProps, nextState)
他的返回值可以決定是否重新渲染, 當 props 或 state 發生變化時,shouldComponentUpdate() 會在渲染執行之前被調用。返回值默認為 true。首次渲染或使用 forceUpdate() 時不會調用該方法。
這是一個性能優化的生命周期方法, 只有當你清楚的知道自己在做什麼的是使用
static getDerivedStateFromProps(props, state)
getDerivedStateFromProps 會在調用 render 方法之前調用,並且在初始掛載及後續更新時都會被調用。它應返回一個對象來更新 state,如果返回 null 則不更新任何內容。
getSnapshotBeforeUpdate(prevProps, prevState)
getSnapshotBeforeUpdate() 在最近一次渲染輸出(提交到 DOM 節點)之前調用。它使得組件能在發生更改之前從 DOM 中捕獲一些資訊(例如,滾動位置)。此生命周期的任何返回值將作為參數傳遞給 componentDidUpdate()。
此用法並不常見,但它可能出現在 UI 處理中,如需要以特殊方式處理滾動位置的聊天執行緒等。
與錯誤相關的生命周期
static getDerivedStateFromError()
此生命周期會在後代組件拋出錯誤後被調用。 它將拋出的錯誤作為參數,並返回一個值以更新 state
注意
getDerivedStateFromError() 會在渲染階段調用,因此不允許出現副作用。 如遇此類情況,請改用 componentDidCatch()。
componentDidCatch()
此生命周期在後代組件拋出錯誤後被調用。 它接收兩個參數:
- error —— 拋出的錯誤。
- info —— 帶有 componentStack key 的對象,其中包含有關組件引發錯誤的棧資訊。
componentDidCatch() 會在「提交」階段被調用,因此允許執行副作用。 它應該用於記錄錯誤之類的情況.