什么是生命周期函數(shù)
- 組件中在某個階段會自動執(zhí)行的函數(shù)。
- 比如我們執(zhí)行使用render函數(shù),在prop或者state變化時,render函數(shù)自動執(zhí)行。
- 因此render函數(shù)就是一個生命周期函數(shù)。
- constructor在組件創(chuàng)建的時候也會自動調(diào)用。但是他不是react獨有,是es6中的函數(shù)所以,我們不將他列為生命周期函數(shù)。
生命周期分為4個階段
- initialization(組件初始化)
- 我們在創(chuàng)建組件的時候需要繼承react Component這個基類,也就繼承這個react的基類,才能有render(),生命周期等方法可以使用,這也說明為什么函數(shù)組件不能使用這些方法的原因。同時也讓組件能使用setState方法。
- 然后我們在 constructor 構(gòu)造函數(shù)中使用 super(props)來將父組件傳遞的props注入給這個組件,以及使用this.state初始化這個組件的屬性。
- 這一系列動作就是組件的初始化。
- mount (組件的掛載)
- 此階段分為三個時期
-
componentWillMount(掛載之前)
- 這個函數(shù)在組件掛載到DOM之前的時候執(zhí)行,所以你在這里引用setState方法,是不會引起組件的重新渲染。
- 同樣這里做的事情如果放在constructor構(gòu)造函數(shù)中去使用也是可以的。
- 這個函數(shù)只會被調(diào)用一次,就是組件掛載到DOM之前的時候。其他時候是不會觸發(fā)這個函數(shù)的。
-
render(掛載中)
- 根據(jù)組件的props和state是否變化,變化即執(zhí)行,這里的變化要注意,并不是值變化。只要重新賦值,新舊值相同也會執(zhí)行。
- 然后return 一個React元素(描述組件,即UI),不負(fù)責(zé)組件實際渲染工作,之后由React自身根據(jù)此元素去渲染出頁面DOM。render是純函數(shù)(Pure function:函數(shù)的返回結(jié)果只依賴于它的參數(shù);函數(shù)執(zhí)行過程里面沒有副作用。
- 不能在里面執(zhí)行this.setState,會有改變組件狀態(tài)的副作用。
-
componentDidMount(掛載完成)
- 約定將ajax請求放在這個生命周期函數(shù)中
- 組件掛載到DOM后被執(zhí)行,只會執(zhí)行一次。
-
- 此階段分為三個時期
- update (組件更新時)
首先我們來了解一下什么時組件更新。只有在通過setState函數(shù)使sate和props變化或重新賦值時才叫組件更新。
setState引起父組件的render函數(shù)執(zhí)行,同時也會引起它的子組件的render函數(shù)執(zhí)行。
原因是react虛擬DOM的diff算法,同級比較原理。
只要重新賦值就是組件更新,如果值并沒有變,也更新組件,這樣就會耗性能,也是我們講同級比較的時候說的一個弊端。
-
接下來我們了解一下有那些周期函數(shù)
-
componentWillReceiveProps(nextProps)
- 此方法只調(diào)用于props引起的組件更新過程中,參數(shù)nextProps是父組件傳給當(dāng)前組件的新props。但父組件render方法的調(diào)用不能保證重傳給當(dāng)前組件的props是有變化的,所以在此方法中根據(jù)nextProps和this.props來查明重傳的props是否改變,以及如果改變了要執(zhí)行啥,比如根據(jù)新的props調(diào)用this.setState出發(fā)當(dāng)前組件的重新render
-
shouldComponentUpdate(nextProps, nextState)
- 此方法通過比較nextProps,nextState及當(dāng)前組件的this.props,this.state,返回true時當(dāng)前組件將繼續(xù)執(zhí)行更新過程,返回false則當(dāng)前組件更新停止,以此可用來減少組件的不必要渲染,優(yōu)化組件性能。ps:這邊也可以看出,就算componentWillReceiveProps()中執(zhí)行了this.setState,更新了state,但在render前(如shouldComponentUpdate,componentWillUpdate),this.state依然指向更新前的state,不然nextState及當(dāng)前組件的this.state的對比就一直是true了。
-
componentWillUpdate(nextProps, nextState)
- 此方法在調(diào)用render方法前執(zhí)行,在這邊可執(zhí)行一些組件更新發(fā)生前的工作,一般較少用。
-
render
- render方法在上文講過,這邊只是重新調(diào)用。
-
componentDidUpdate(prevProps, prevState)
- 此方法在組件更新后被調(diào)用,可以操作組件更新的DOM,prevProps和prevState這兩個參數(shù)指的是組件更新前的props和state
-
- 優(yōu)化弊端
- 1.當(dāng)因為父組件重新render,使得props重新被賦值,導(dǎo)致子組件跟著渲染.
/**
* 方法一:解決上述弊端,可以在shouldComponentUpdate函數(shù),組件更新前進(jìn)行判斷,props是否改變,再確定是否執(zhí)行重新渲染。
*/
class Child extends Component {
shouldComponentUpdate(nextProps){
if(nextProps.value === this.props.value){
return false
}
return true
}
render() {
return <div>{this.props.value}</div>
}
}
/**
* 方法二:
* 1.解決上述弊端,也可以先將this.props.value賦值給子組件的state
* 2.再在componentWillReceiveProps函數(shù)中,使用setState去重新給stae中的屬性賦值this.props.value
* 3.文檔中提到,在該函數(shù)(componentWillReceiveProps)中調(diào)用 this.setState() 將不會引起第二次渲染。
* 4.因為componentWillReceiveProps是在props有變化的時候才會觸發(fā),所以在這里面做this.setState()一定是有改變state
*/
//
class Child extends Component {
constructor(props) {
super(props);
this.state = {
value: props.value // 先將this.props.value賦值給子組件的state
};
}
componentWillReceiveProps(nextProps) { // 在props有變化的時候才會觸發(fā)這個方法
this.setState({value: nextProps.value}); // 重新賦值,引起render
}
render() {
return <div>{this.state.value}</div>
}
}
- 2.組件本身調(diào)用setState方法,但是并沒有改變state中的值。
/**
* 也是通過shouldComponentUpdate判斷新舊值是否改變,改變才做render
*/
class Test extends Component {
constructor(props) {
super(props);
this.state = {
value:1
}
}
shouldComponentUpdate(nextState){ // 應(yīng)該使用這個方法判斷新舊值是否改變
if(nextState.value === this.state.value){
return false // 沒有改變返回false
}
return true
}
changeState = () => { // 雖然調(diào)用了setState ,但state并無變化
const value = this.state.value
this.setState({
value
})
}
render() {
return <div onClick = {this.changeState}>{this.state.value}</div>
}
}
- 卸載階段(componentWillUnmount)
- 只有一個生命周期方法componentWillUnmount
- 此方法在組件被卸載前調(diào)用,可以在這里執(zhí)行一些清理工作,比如清楚組件中使用的定時器,清楚componentDidMount中手動創(chuàng)建的DOM元素等,以避免引起內(nèi)存泄漏。
- 在react組件中,除了render函數(shù),其他任何生命周期函數(shù)都可以不寫,因為組件繼承了react中的 Component,Component內(nèi)置了其他的生命周期函數(shù)