前言:React 的版本從 v15 到 v16.3 ,再到v16.4,現在最新的版本是 v16.8了。其中最大的變化可能是React Hooks
的加入,而最令人困惑的卻是它的生命週期,新舊生命週期函數混雜在一起,難免會讓許多新來者有很多困惑。所以這一篇我們來分析一下 React 生命週期的演變及原因,進一步理解其使用。
組件生命週期的四個階段
- Initialization (初始化階段:組件實例的創建)
- Mounting (加載階段:組件插入 dom中)
- Updating (更新階段:屬性或狀態每改變一次都將會觸發一次,組件重新渲染。)
- Unmounting (卸載階段:組件卸載和銷燬)
老版生命週期(16.3之前的生命週期)
Initialization (初始化階段:涉及4個鉤子函數)
這些方法會在組件初始化的時候被調用,只跟實例的創建有關。
如果用createReactClass
進行創建,則還有getInitialState
這些生命週期函數,但很少使用,我們這裏不提及。
static defaultProps{} (getDefaultProps())
定義默認props
,會和父組件傳下來的props
進行合併,且以父組件中的props
優先級更高,相當於{...defaultProps, props}
。
static propTypes{} (getInitialState())
定義props
的數據類型,可以幫助我們確定其有效性,減少許多開發中不必要的錯誤。
constructor()
在加載階段前調用一次,進行 state 的初始化。
constructor(props){
super(props)
}
super(props)
用來調用父類的構建方法。
Mounting (加載階段:涉及3個鉤子函數)
componentWillMount()
新版中爲UNSAFE_componentWillMount()
。
只在組件加載時調用,整個生命週期只調用一次,以後組件更新也不會調用,此時可以修改 state。
render()
react
中最重要的生命週期函數,創建虛擬 dom,並進行 diff
算法,更新 dom 樹也在此進行。所以不應該在此改變組件的狀態或者與瀏覽器進行交互。
注意:這個函數不能缺少,如果不創建虛擬 dom,可以return null
。
componentDidMount()
組件加載完成後立即調用,整個生命週期只調用一次,可以獲取到更新後的 DOM,在此處可以進行網絡請求等。
Updating (更新階段:涉及5個鉤子函數)
componentWillReceiveProps()
新版中爲UNSAFE_componentWillReceiveProps()
。
在組件加載後,如果有新的props
傳遞過來,會先調用這個函數,可以在這裏調用setState()
修改state
。
componentWillReceiveProps(nextProps)
shouldComponentUpdate()
react
中一個重要的性能優化點,組件接收到新的props
或者state
,返回true
表示需要更新 dom,返回false
阻止更新。
shouldComponentUpdate(nextProps, nextState)
componentWillUpdate()
新版中爲UNSAFE_componentWillUpdate()
。
組件加載時不調用,只有在組件需要更新(即shouldComponentUpdate
返回true
)時調用。
componentWillUpdate(nextProps, nextState)
注意:不能在這個方法中調用setState()
修改state
。
render()
同上。
componentDidUpdate()
在組件更新完成後立即被調用,可以進行網絡請求等。
componentDidUpdate(prevProps, prevState)
Unmounting (卸載階段:涉及1個鉤子函數)
componentWillUnmount()
在組件被卸載和銷燬之前調用,可以在這裏處理任何必要的清理工作,比如解除定時器,取消已經發起的網絡請求,清理在componentDidMount
函數中創建的 DOM 元素。
componentWillUnmount()
Error Handling(錯誤處理:涉及1個鉤子函數)
componentDidCatch()
錯誤邊界捕獲,在v16.0剛推出的時候新增加的一個生命週期函數,用於捕獲在子組件樹中任意地方發生的 JavaScript 錯誤,一個錯誤邊界不能捕獲它自己內部的錯誤。
componentDidCatch(error, info)
組件的基本寫法
import React, {Component} from 'React'
export default class OldReactComponent extends Componet{
static defaultProps={}
static propTypes={}
constructor(props){
super(props)
}
state={}
componentWillMount(){}
render(){
return null
}
componentDidMount(){}
componentWillReceivePorps(nextProps){}
componentShouldUpdate(nextProps,nextState){
return true
}
componentWillUpdate(nextProps,nextState){}
componentDidUpdate(){}
componentWillUnmount(){}
}
新版生命週期(16.4之後的生命週期)
(帶UNSAFE_
的函數在以後將會被丟棄,官方也不建議使用,這裏不再列出。)
新版本中,新增了三個生命週期函數:
- static getDerivedStateFromProps()
- getSnapshotBeforeUpdate
- static getDerivedStateFromError()
同時deprecate了一組生命週期API,包括:
- componentWillReceiveProps
- componentWillMount
- componentWillUpdate
可以看出除了shouldComponentUpdate
之外,render
之前的所有生命週期都被消滅了。原因是這些生命週期太多時候沒有被正確使用,而且在Fiber
之後,如果要開啓async rendering
,在render
函數之前的所有函數,都有可能被執行多次。
Initialization (初始化階段:涉及4個鉤子函數)
同上。
Mounting (加載階段:涉及3個鉤子函數)
static getDerivedStateFromProps()
因爲是靜態方法,所以無法訪問到組件實例。每次組件調用render
前都會被調用,獲取新的props
和state
(v16.3只會爲props
的而調用,v16.4修正爲props
和state
)之後,返回一個對象作爲新的state
,如果返回null
則表示不需要更新;配合componentDidUpdate,可以覆蓋componentWillReceiveProps的所有用法。並且它應該是個純函數,沒有副作用(side effect)。
static getDerivedStateFromProps(props,state)
render()
同上。
componentDidMount()
同上。
Updating (更新階段:涉及5個鉤子函數)
static getDerivedStateFromProps()
同上。
shouldComponentUpdate()
同上。
render()
同上。
getSnapshotBeforeUpdate()
觸發時間: update發生的時候,在render之後,在組件dom渲染之前;返回一個值,作爲componentDidUpdate的第三個參數;配合componentDidUpdate, 可以覆蓋componentWillUpdate的所有用法,常用於 scroll 位置的定位。
getSnapshotBeforeUpdate(prevProps, prevState)
componentDidUpdate()
同上。
Unmounting (卸載階段:涉及1個鉤子函數)
componentWillUnmount()
同上。
Error Handling(錯誤處理:涉及2個鉤子函數)
componentDidCatch()
同上。
static getDerivedStateFromError()
用於在“render”階段(非render
函數)的錯誤捕獲,應該是個純函數,沒有副作用(side effect)。
static getDerivedStateFromError(error)
組件的基本寫法
import React, {Component} from 'React'
export default class OldReactComponent extends Componet{
static defaultProps={}
static propTypes={}
constructor(props){
super(props)
}
state={}
static getDerivedStateFromProps(props,state){}
render(){
return null
}
componentDidMount(){}
componentShouldUpdate(nextProps,nextState){
return true
}
getSnapshotBeforeUpdate(prevProps, prevState){}
componentDidUpdate(){}
componentWillUnmount(){}
}
總結
- React新的生命週期新增
static getDerivedStateFromProps
、getSnapshotBeforeUpdate
並棄用componentWillMount
,componentWillReceiveProps
,componetWillUpdate
(這三個函數將在 React 17中刪除)。 - 新增
static getDerivedStateFromError
捕獲“render”階段的錯誤。
參考
幫你理清React的生命週期
清晰大圖請點擊這裏