React 組件的生命周期
React.js 將組件渲染,并且構(gòu)造 DOM 元素然后塞入頁面的過程稱為組件的掛載。這一節(jié)我們學(xué)習(xí)了 React.js 控制組件在頁面上掛載和刪除過程里面幾個(gè)方法:
componentWillMount:組件掛載開始之前,也就是在組件調(diào)用 render 方法之前調(diào)用。
componentDidMount:組件掛載完成以后,也就是 DOM 元素已經(jīng)插入頁面后調(diào)用。
componentWillUnmount:組件對(duì)應(yīng)的 DOM 元素從頁面中刪除之前調(diào)用。
現(xiàn)在我們應(yīng)該知道一件事情, 有了 組件 和 props, 我們就可以把一個(gè)頁面拆成一個(gè)個(gè)小組件.
有了 內(nèi)部狀態(tài), 我們就可以讓組件在某些時(shí)候做出一些變化.
我們的頁面就是通過一個(gè)個(gè)小的組件, 組合成一個(gè)大的組件, 一份份小的 jsx, 組合成一份大的 jsx.
最后交給 ReactDOM.render(), 通過 DOM 操作, 把 Virtual DOM 渲染成瀏覽器真實(shí)的 DOM.
理解生命周期
掛載階段
組件也是有生命的, 如果一個(gè)組件被渲染到了頁面, 那么這個(gè)組件的生命便開始了.
也就是 Virtual DOM 變成真實(shí) DOM的這個(gè)過程. 組件生命的開始也叫組件的掛載.
上代碼:
import React from 'react';
import ReactDOM from 'react-dom';
class A extends React.Component {
render(){
return (
<div>
<p> 數(shù)字: 999 </p>
<button>click once</button>
</div>
)
}
}
ReactDOM.render(
<div>
<A/>
</div>
, document.getElementById('root'));
<A/> 開始的時(shí)候還只是一份虛擬dom, 可一旦把它渲染到瀏覽器, 我們便說這個(gè)組件被掛載了.
更新階段
說白了就是 setState 導(dǎo)致 React.js 重新渲染組件并且把組件的變化應(yīng)用到 DOM 元素上的過程,這是一個(gè)組件的變化過程。
一個(gè)被掛載的組件, 某些時(shí)候可能會(huì)變化, 也就是被更新:
class A extends React.Component {
constructor(props){
super(props);
this.state = {
num: Math.random().toString().slice(2, 8)
};
}
changeNum=()=>{
this.setState({
num: Math.random().toString().slice(2, 8)
});
}
render(){
let {num} = this.state;
return (
<div>
<p> 數(shù)字: {num} </p>
<button
onClick={this.changeNum}
>click once</button>
</div>
)
}
}
我們改造下 A 組件. 每次點(diǎn)擊按鈕, 數(shù)字就會(huì)改變. 也就是這個(gè)組件會(huì)變化, 這個(gè)時(shí)候, 我們就說這個(gè)組件被更新了.
卸載階段 當(dāng)一個(gè)已經(jīng)被掛載的組件從頁面刪除掉, 那么這個(gè)組件實(shí)例的生命就結(jié)束了. 我們就說這個(gè)組件被卸載了.
我們改一下上面的代碼:
class B extends React.Component{
render(){
return (
<div>我是組件 B</div>
)
}
}
class A extends React.Component {
constructor(props){
super(props);
this.state = {
isShowB: true
};
}
changeNum=()=>{
this.setState({
isShowB: !this.state.isShowB
});
}
render(){
let {isShowB} = this.state;
return (
<div>
{
isShowB ? (
<B/>
) : (
<p>我不是B</p>
)
}
<button
onClick={this.changeNum}
>click once</button>
</div>
)
}
}
在第一次點(diǎn)擊按鈕之前, 有一個(gè) B 組件的實(shí)例被掛載到頁面, 而點(diǎn)擊按鈕之后, 這個(gè) B 組件實(shí)例就會(huì)被卸載掉.
重復(fù)的點(diǎn)擊按鈕, 就會(huì)不斷有新的 B 組件實(shí)例被掛載, 然后被卸載.
生命周期函數(shù)
無論是組件掛載, 更新, 還是卸載. 都是一個(gè)瞬間的事情. 但是在這個(gè)瞬間執(zhí)行之前和之后, React 會(huì)調(diào)用一些函數(shù), 我們把這些函數(shù)叫做生命周期函數(shù).
Mounting(掛載) 階段
- 組件掛載時(shí)首先執(zhí)行
- 在這里可以:
- 初始化 state
- 給事件函數(shù)綁定
this
-
componentWillMount()- 組件將要掛載時(shí)執(zhí)行
-
render()- 返回此刻組件的 JSX 結(jié)構(gòu)
-
componentDidMount()- 組件掛載完成后執(zhí)行
- 在這里可以:
- 開啟定時(shí)器
- 發(fā)起請(qǐng)求
- 訪問真實(shí)的 DOM 元素
這些函數(shù)是組件掛載階段執(zhí)行的函數(shù).
因?yàn)橐粋€(gè)組件實(shí)例只能被出生一次, 也就是一生只能被掛載一次, 所以這些函數(shù)在這個(gè)組件實(shí)例的生命周期中只會(huì)執(zhí)行一次.
當(dāng)然, render() 函數(shù)是個(gè)例外. 在掛載階段它需要返回 JSX 結(jié)構(gòu), 在更新階段, 它也需要返回新的 JSX 結(jié)構(gòu). 所以 render()可能會(huì)執(zhí)行多次.
Updateing(更新) 階段
-
componentWillReceiveProps( nextProps )- 父組件更新的時(shí)候執(zhí)行
-
shouldComponentUpdate( nextProps, nextState )- 返回 bool 值, 默認(rèn)返回
true - 如果返回 false, 當(dāng)前組件不會(huì)更新, 之后的生命周期函數(shù)不執(zhí)行
- 性能優(yōu)化的主要手段之一
- 返回 bool 值, 默認(rèn)返回
// 更新前執(zhí)行的,所以在沒有更新之前
shouldComponentUpdate(nP,nS){
return !this.props.content === nP.content
}
-
componentWillUpdate( nextProps, nextState )- 組件將要更新時(shí)執(zhí)行
render()-
componentDidUpdate( prevProps, prevState )- 組件更新之后執(zhí)行
Unmounting(卸載) 階段
-
componentWillUnmount()- 組件將要卸載的時(shí)候執(zhí)行
- 可以在這里:
- 移除事件綁定
- 清空定時(shí)器
- 取消請(qǐng)求
- 可以在這里:
- 組件將要卸載的時(shí)候執(zhí)行
很長一段時(shí)間, 組件的生命周期就是 掛載, 更新, 卸載三個(gè)階段.
在更新到了 16.0.0 之后, 新增了一個(gè) 錯(cuò)誤處理的階段.
新增了一個(gè)函數(shù):
componentDidCatch( error, info )
當(dāng)子組件的生命周期函數(shù)(包括 render(), constructor()和其他生命周期函數(shù))里面拋出了錯(cuò)誤, 那么這個(gè)函數(shù)就會(huì)執(zhí)行.
注意, 在此組件之下的子組件發(fā)生錯(cuò)誤的時(shí)候才會(huì)執(zhí)行, 組件自身的生命周期函數(shù)發(fā)生錯(cuò)誤不會(huì)捕獲到.
關(guān)于生命周期函數(shù)
在上面我們初步了解了組件的生命周期函數(shù), 并且我在每個(gè)生命周期函數(shù)的下面做了簡單的說明.
現(xiàn)在我們只要知道生命周期函數(shù)會(huì)在什么之后執(zhí)行就可以了.
有些生命周期會(huì)頻繁使用, 而有些則會(huì)很少用到.
關(guān)于如何生命周期函數(shù)在什么時(shí)候用這種問題, 這需要隨著時(shí)間, 隨著你解決各種業(yè)務(wù)需求之后, 會(huì)慢慢越來越有體會(huì).
現(xiàn)在, 你還不需要太關(guān)心這方面的問題.
