React 生命周期簡介
- 裝載過程:組件實例被創建和插入 DOM 樹的過程;
- 更新過程:組件被重新渲染的過程;
- 卸載過程:組件從 DOM 樹中刪除的過程。
註意:裝載過程與卸載過程在組件的生命周期中只會執行一次,更新過程可以多次執行。
在這三個過程中,分別依次調用了組件的生命周期函數。
React 組件生命周期總體流程圖如下:
一、裝載過程
在這個過程中組件被創建,裝載過程在組件的生命周期中只會被執行一次,調用的生命周期函數有:
- defaultProps / getDefaultProps()
- constructor() / getInitialState()
- componentWillMount()
- render()
- conponentDidMount()
1、defaultProps:
組件類的一個靜態屬性,嚴格來講這裏不屬於組件的生命周期的一部分,用於設置組件 props 的默認值。
class Counter extends Component {
static defaultProps = {
count: 0,
};
render() {
return (
<div>當前值為:{this.props.count}</div>
);
}
};
在調用組件時如果未設置 props.count,這樣 props.count === undefined , 其將被設置默認為 0 :
render() {
return <Counter /> ; // 渲染後顯示為 0
}
如果調用組件時設置 props.count={null} , 這樣渲染出來為 null :
render() {
return <Counter count={null} /> ; // 渲染後顯示為 null
}
他是在執行 React 的 createElement() 時去獲取並賦值給 props 的,發生在組件實例化之前。
2、constructor
constructor 是 ES6 中 class 的構造函數,組件初始化調用的,所以它在組件生命周期函數中最先執行,這裏主要做下面兩件事情:
- 初始化組件的 state。 它是組件初始化實例時最先執行的一個函數,因此在這裏初始化 state ;
- 方法的綁定。在 ES6 語法下,類的每個成員函數在執行時的 this 指向並不是和類的實例自動綁定的, 而構造函數中,this指向就是當前組件實例,為了方便將來調用,往往在構造函數中將組件實例的函數使用 bind(this) 這種方式,讓當前實例中的函數調用時,this 始終是指向當前組件實例。
class Counter extends Component {
// 設置默認 props 的值
static defaultProps = {
count: 0,
};
// 構造函數 construcor
constructor(props) {
super(props);
this.state = {
count: 0,
};
this.handleIncrease = this.handleIncrease.bind(this);
}
// 點擊增加1
handleIncrease(){
let addCounter = this.state.counter;
this.setState({
counter: addCounter + 1
})
}
render() {
return (
<div>
當前 props 值為:{this.props.count}
<br />
當前 state 值為:{this.state.counter}
<button onClick={this.handleIncrease}>點擊增加</button>
</div>
);
}
};
3、componentWillMount
準備裝載組件。它在組件實例化並初始化數據完成以後,組件 render() 之前調用。
官方文檔說避免在該方法中引入任何的副作用或訂閱,所以我們不建議在此生命周期函數內獲取數據或修改 state; 如果有需求在 render() 前一定要修改 state,最好是在 constructor 裏進行。
4、render
確定需要更新組件時調用 render,根據 diff 算法,渲染界面,生成需要更新的虛擬 DOM 數據。它並不做實際的渲染動作,只是返回了一個 JSX 描述結構,最終是由 React 來操作渲染過程。
render 函數是 React 組件中最重要的函數,一個組件中可以沒有其他的生命周期函數,但一定要有 render 函數,如果一個組件沒有東西可呈現,這個組件的 render 函數定義返回 null 或 false;
render() 是一個純函數,所以在此聲明周期內不能 setState。
5、componentDidMount
在組件裝載後調用。這時已經生成了真實的 DOM 節點。
在這個函數中我們可以獲取數據,改變狀態,直接改變 DOM 等操作。
註意:並不是在調用 render() 函數之後立即調用了此函數,調用 render() 函數只是返回了一個 JSX 對象供 React 調用決定如何渲染,在 React 庫把所有組件渲染完成再完成裝載,這時才會依次調用各個組件的 componentDidMount 函數,表示這個組件已經掛載到 DOM 上了。
以上裝載過程的生命周期函數只會執行一次
二、更新過程
更新過程中依次執行的生命周期函數有:
- componentWillReceiveProps
- shouldComponentUpdate
- componentWillUpdate
- render
- componentDidUpdate
並不是每次更新都會依次調用以上全部函數,會根據不同的變化依次執行相關的函數。
1、componentWillReceiveProps(nextProps)
子組件的 props 發生改變及父組件的 render 函數被調用都會觸發子組件的此函數。我們可以根據 nextProps 同步本地的 state,但最好要先比較 this.props 與 nextPorps 在做操作。
本組件中通過 this.setState 方法觸發的更新不會觸發此函數。
2、shouldComponentUpdate(nextProps, nextState)
當組件接收到新的 props 和 state 改變的話,都會觸發調用,返回 Boolean,默認返回的是 true。
返回 true 繼續進行下面的生命周期函數;返回 false 不更新組件。
這個組件中不允許改變 state。
我們可以利用此特點來優化項目,避免不必要的渲染,提高性能。
shouldComponentUpdate(nextProps, nextState) {
return this.props.count !== nextProps.count || this.state.counter !== nextState.counter;
}
3、componentWillUpdate
在 shouldComponentUpdate 函數返回 true 時,會依次調用 componentWillUpdate、render 和 componentDidUpdate 函數。
此函數內不可以改變 state,如果需要更新狀態,請在 componentWillReceiveProps 中調用 this.setState()。
4、render
這次 render() 和裝載階段的 render() 沒有區別,只不過是在不同的階段調用。
前一個 render 是在組件第一次加載時調用的,也就是初次渲染;
後一個 render 是除去第一次之後調用的,也就是再渲染。
5、componentDidUpdate
在組件再次渲染之後調用的。和 componentDidMount 一樣,在這個函數中可以使用 this.refs 獲取真實 DOM。
此函數內不可以改變 state
三、卸載階段
componentWillUnmount
當組件要被從界面上移除的時候,就會調用。
在這個函數中,可以做一些組件相關的清理工作,例如取消計時器、網絡請求等。
代碼 github 地址:https://github.com/mqp0713/react-lifestyle
React 生命周期簡介