本文詳細介紹了 React 生命週期的用法以及各個階段的生命週期進行,而且用實例代碼作了詳細演示。代碼位置html
上圖是基於 React 16.4 以後的生命週期圖解。如感受不對,請先查看 React 版本react
在 React 組件掛載以前被調用,實現 React.Component
的子類的構造函數時,要在第一行加上 super(props)。git
React 構造函數一般只用於兩個目的:github
this.state
來初始化本地 state
若是沒有初始化狀態(state
),而且沒有綁定方法,一般不須要爲 React
組件實現一個構造函數。瀏覽器
不須要在構造函數中調用
setState()
,只需將初始狀態設置給this.state
便可 。性能優化
getDerivedStateFromProps
在每次調用 render 方法以前調用。包括初始化和後續更新時。網絡
包含兩個參數:第一個參數爲即將更新的
props
值,第二個參數爲以前的state
值函數
返回值:返回爲
null
時,不作任何反作用處理。假若想更新某些state
狀態值,則返回一個對象,就會對state
進行修改性能
該生命週期是靜態函數,屬於類的方法,其做用域內是找不到
this
的測試
render()
方法是類組件中惟一必須的方法,其他生命週期不是必需要寫。 組件渲染時會走到該生命週期,展現的組件都是由 render() 生命週期的返回值來決定。
注意: 若是 shouldComponentUpdate() 方法返回 false ,render() 不會被調用。
在 React 組件裝載(mounting)(插入樹)後被當即調用。
componentDidMount 生命週期是進行發送網絡請求、啓用事件監聽的好時機
若是有必要,能夠在今生命週期中馬上調用 setState()
在組件準備更新以前調用,能夠控制組件是否進行更新,返回 true 時組件更新,返回 false 組件不更新。
包含兩個參數,第一個是即將更新的 props 值,第二個是即將跟新後的 state 值,能夠根據更新先後的 props 或 state 進行判斷,決定是否更新,進行性能優化
不要
shouldComponentUpdate
中調用 setState(),不然會致使無限循環調用更新、渲染,直至瀏覽器內存崩潰
getSnapshotBeforeUpdate()
在最近一次的渲染輸出被提交以前調用。也就是說,在 render 以後,即將對組件進行掛載時調用。
它可使組件在 DOM 真正更新以前捕獲一些信息(例如滾動位置),今生命週期返回的任何值都會做爲參數傳遞給
componentDidUpdate()
。如不須要傳遞任何值,那麼請返回 null
componentDidUpdate()
在更新發生以後當即被調用。這個生命週期在組件第一次渲染時不會觸發。
能夠在今生命週期中調用 setState(),可是必須包含在條件語句中,不然會形成無限循環,最終致使瀏覽器內存崩潰
componentWillUnmount()
在組件即將被卸載或銷燬時進行調用。
今生命週期是取消網絡請求、移除監聽事件、清理 DOM 元素、清理定時器等操做的好時機
注意: componentWillMount()、componentWillUpdate()、componentWillReceiveProps() 即將被廢棄,請不要再在組件中進行使用。所以本文不作講解,避免混淆。
constructor()
static getDerivedStateFromProps()
render()
componentDidMount()
static getDerivedStateFromProps()
shouldComponentUpdate()
render()
getSnapshotBeforeUpdate()
componentDidUpdate()
shouldComponentUpdate()
render()
getSnapshotBeforeUpdate()
componentWillUnmount()
下面根據一個父子組件的props 改變、state 改變以及子組件的掛載/卸載等事件,對各生命週期執行順序進行理解,有興趣的同窗能夠一塊兒看一下,也能夠下載代碼本身進行測試。
import React, { Component } from 'react';
import Child from './Child.js';
const parentStyle = {
padding: 40,
margin: 20,
border: '1px solid pink'
}
const TAG = "Parent 組件:"
export default class Parent extends Component {
constructor(props) {
super(props);
console.log(TAG, 'constructor');
this.state = {
num: 0,
mountChild: true
}
}
static getDerivedStateFromProps(nextProps, prevState) {
console.log(TAG, 'getDerivedStateFromProps');
return null;
}
componentDidMount() {
console.log(TAG, 'componentDidMount');
}
shouldComponentUpdate(nextProps, nextState) {
console.log(TAG, 'shouldComponentUpdate');
return true;
}
getSnapshotBeforeUpdate(prevProps, prevState) {
console.log(TAG, 'getSnapshotBeforeUpdate');
return null;
}
componentDidUpdate(prevProps, prevState, snapshot) {
console.log(TAG, 'componentDidUpdate');
}
componentWillUnmount() {
console.log(TAG, 'componentWillUnmount');
}
/** * 修改傳給子組件屬性 num 的方法 */
changeNum = () => {
let { num } = this.state;
this.setState({
num: ++ num
});
}
/** * 切換子組件掛載和卸載的方法 */
toggleMountChild = () => {
let { mountChild } = this.state;
this.setState({
mountChild: !mountChild
});
}
render() {
console.log(TAG, 'render');
const { num, mountChild } = this.state;
return (
<div style={ parentStyle }> <div> <p>父組件</p> <button onClick={ this.changeNum }>改變傳給子組件的屬性 num</button> <br /> <br /> <button onClick={ this.toggleMountChild }>卸載 / 掛載子組件</button> </div> { mountChild ? <Child num={ num } /> : null } </div> ) } } 複製代碼
import React, { Component } from 'react'
const childStyle = {
padding: 20,
margin: 20,
border: '1px solid black'
}
const TAG = 'Child 組件:'
export default class Child extends Component {
constructor(props) {
super(props);
console.log(TAG, 'constructor');
this.state = {
counter: 0
};
}
static getDerivedStateFromProps(nextProps, prevState) {
console.log(TAG, 'getDerivedStateFromProps');
return null;
}
componentDidMount() {
console.log(TAG, 'componentDidMount');
}
shouldComponentUpdate(nextProps, nextState) {
console.log(TAG, 'shouldComponentUpdate');
return true;
}
getSnapshotBeforeUpdate(prevProps, prevState) {
console.log(TAG, 'getSnapshotBeforeUpdate');
return null;
}
componentDidUpdate(prevProps, prevState, snapshot) {
console.log(TAG, 'componentDidUpdate');
}
componentWillUnmount() {
console.log(TAG, 'componentWillUnmount');
}
changeCounter = () => {
let { counter }= this.state;
this.setState({
counter: ++ counter
});
}
render() {
console.log(TAG, 'render');
const { num } = this.props;
const { counter } = this.state;
return (
<div style={ childStyle }> <p>子組件</p> <p>父組件傳過來的屬性 num : { num }</p> <p>自身狀態 counter : { counter }</p> <button onClick={ this.changeCounter }>改變自身狀態 counter</button> </div>
)
}
}
複製代碼
父子組件第一次進行渲染加載時,界面展現爲:
控制檯中的 log 打印順序爲:
點擊子組件中的 改變自身狀態 按鈕,則界面上 自身狀態 counter: 的值會 + 1,控制檯中的 log 打印順序爲:
點擊父組件中的 改變傳給子組件的屬性 num 按鈕,則界面上 父組件傳過來的屬性 num: 的值會 + 1,控制檯中的 log 打印順序爲:
點擊父組件中的 卸載 / 掛載子組件 按鈕,則界面上子組件會消失,控制檯中的 log 打印順序爲:
再次點擊父組件中的 卸載 / 掛載子組件 按鈕,則界面上子組件會從新渲染出來,控制檯中的 log 打印順序爲:
當子組件自身狀態改變時,不會對父組件產生反作用的狀況下,父組件不會進行更新,即不會觸發父組件的生命週期
當父組件中狀態發生變化(包括子組件的掛載以及)時,會觸發自身對應的生命週期以及子組件的更新
render 以及 render 以前的生命週期,則 父組件 先執行
render 以及 render 以後的聲明週期,則子組件先執行,而且是與父組件交替執行
當子組件進行卸載時,只會執行自身的 componentWillUnmount 生命週期,不會再觸發別的生命週期
可能總結的很差,不是很完整。只是根據通常狀況進行的總結。有不妥之處,但願各位朋友可以多多指正。
源碼地址(歡迎 Star,謝謝!)
還沒看夠?移步至:React Component 官網