目錄
生命週期
React的生命週期有新版(React 16.3+)和舊版
新版新增2個,計畫廢棄3個hook(componentWillMount、componentWillUpdate、componentWillReceiveProps)
之所以說計畫是因為直到18.2的現在仍未完全棄用,只要加上UNSAFE_還是能用,但UNSAFE_和安全性並無關
廢棄的原因是React未來要朝非同步渲染走,而那些hook可能被濫用導致生成滿滿的bug
本文的生命週期是指新版的,可以粗分為3個階段
當組件的實例被建立且加入DOM時,生命週期會依照下列的順序被呼叫
mounting
constructor- static getDerivedStateFromProps(少用)
rendercomponentDidMount
updating
- static getDerivedStateFromProps(少用)
- shouldComponentUpdate(少用)
render- getSnapshotBeforeUpdate(少用)
- componentDidUpdate
unmounting
componentWillUnmount
render時發生錯誤則會呼叫以下方法
- static getDerivedStateFromError
- componentDidCatch
常用的hook
constructor
如果沒有初始化state,也不綁定方法的話,就不需要使用this前必須呼叫super(props),否則會報錯"Must call super constructor in derived class before accessing 'this' or returning from derived constructor"
使用這個hook時有幾點需要注意
避免在constructor中產生side effect(ex: 用package的API訂閱、撈資料),需要的話就用componentDidMount
不要複製prop到state,因為props更新時state不會一起被更新,這可能導致bug
constructor(props){ super(props); this.state = {color: props.color} }
render
class component中唯一必要的方法render()必須是
pure,也就是說它不改變state,且每次都回傳同樣的結果shouldComponentUpdate() 回傳的值為false,則render不會被呼叫
如果
父組件在componentDidMount內呼叫setState(),子組件的render會跑2次componentDidMount
組件被掛載後立刻呼叫如果要撈資料的話,官方推薦在此時
打request(componentDidUpdate也可以)
class Child extends Component { constructor(props) { super(props); this.state = { }; } componentDidMount(){ console.log('child did mount'); console.log(this.props.message); } render() { return ( <div> <h1 className='mb-3'>this is child.</h1> <p>{this.props.message}</p> </div> ); } } class Parent extends Component { constructor(props) { super(props); this.state = { message:'this is message from parent constructor' }; } render() { return ( <div> <Child message={this.state.message}></Child> </div> ); } }
如果在父組件撈然後傳過來的話,因為是非同步,所以此時
props還沒傳過來class Child extends Component { constructor(props) { super(props); this.state = { }; } componentDidMount(){ console.log('child did mount'); console.log(this.props.message); } render() { console.log('child render'); return ( <div> <h1 className='mb-3'>this is child.</h1> <p>{this.props.message}</p> </div> ); } } class Parent extends Component { constructor(props) { super(props); this.state = { }; } async componentDidMount(){ console.log('parent did mount'); // 在這呼叫setState()會讓Child render()跑2次 this.setState({ message:await this.getRes() }); } getRes(){ return new Promise((resolve) => { resolve('this is res from this.getRes()'); }); } render() { return ( <div> <Child message={this.state.message}></Child> </div> ); } }在此hook
呼叫setState(),這會觸發一次額外的render,需要慎用,因為可能衝擊效能componentDidUpdate
參數依序是舊的props、舊的state、snapshot,snapshot來自getSnapshotBeforeUpdate的回傳值因為有以上參數,所以如果有打request的話在這個hook進行比較,達成條件時才setState(),以避免無限迴圈
例子可以看以下2篇
componentWillUnmount
組件被移除、實例被消滅前一刻呼叫因為馬上就會到componentDidUnmount,所以
不該在這個階段呼叫setState()在這個階段可以
取消side effect(ex: 計時器、訂閱API)
少用的hook
shouldComponentUpdate
控制資料改變後是否要重新render,初次render不會呼叫,預設為true,回傳false時不重新渲染因為是
淺比較所以如果物件有多層仍可能出錯官方建議使用React.PureComponent代替,因為它有實作這個hook,不必自行撰寫
static getDerivedStateFromProps
組件render前呼叫多用於state依賴於props的狀況,
監聽props改變並更新state需要回傳一個物件,用以更新state,如果不需要更新的話回傳null
getSnapshotBeforeUpdate
重新render前呼叫參數依序是舊的props、state
需要回傳值,
回傳值會傳給componentDidUpdate
React & Vue生命週期
mounting
| React 16.3+ | Vue 2 | Vue 3 composition API | 說明 |
|---|---|---|---|
| constructor | beforeCreate | setup | React實例被初始化,此階段可透過this取用props、state,Vue實例已初始化,但無法透過this取用option |
| created | setup | Vue options(ex: data、props、method...)設置完成 | |
| beforeMount | onBeforeMount | render function將template被轉為virtual DOM,但還未掛載到this.$el | |
| getDerivedStateFromProps | 多用於state依賴於props的狀況,監聽props改變並更新state,需要回傳一個物件,用以更新state |
||
| render | 將virtual DOM渲染成真的DOM | ||
| componentDidMount | mounted | onMounted | 組件被掛到DOM,並設為Vue的this.$el |
updating
| React | Vue2 | Vue 3 composition API | 說明 |
|---|---|---|---|
| getDerivedStateFromProps | 多用於state依賴於props的狀況,監聽props改變並更新state,需要回傳一個物件,用以更新state |
||
| shouldComponentUpdate | 控制資料改變後是否要重新render | ||
| beforeUpdate | onBeforeUpdate | 資料變動使得DOM被patch前呼叫 | |
| render | diff演算法比較virtual DOM的差異,重新渲染不同的地方 | ||
| getSnapshotBeforeUpdate | 資料變動導致重新render前,抓住舊的props、state,並傳給componentDidUpdate | ||
| componentDidUpdate | updated | onUpdated | DOM被更新 |
unmounting
| React | Vue2 | Vue 3 composition API | 說明 |
|---|---|---|---|
| componentWillUnmount | beforeDestroy | onBeforeUnmount | 組件從DOM移除、實例被消滅前,在此取消side effect。React此時可以,但不該呼叫setState,Vue最後一個可以用this操作實例的hook |
| destroyed | onUnmounted | 組件被移除,實例被消滅 |
其他
| React | Vue2 | Vue 3 composition API | 說明 |
|---|---|---|---|
| getDerivedStateFromError | errorCaptured | onErrorCaptured | 捕捉子/孫組件的錯誤 |
| componentDidCatch | errorCaptured | onErrorCaptured | 捕捉子/孫組件的錯誤 |
參考資料
React - React.Component
Vue & React lifecycle method comparison


