React 組件的生命周期

  • 書籍《深入淺出React和Redux》

組件生命周期

React 組件生命周期可能會(huì)經(jīng)歷如下三個(gè)過程:

  • 裝載過程(Mount)- 組件第一次在DOM樹中渲染的過程
  • 更新過程(Update)- 當(dāng)組件被重新渲染的過程
  • 卸載過程(Unmount)- 組件從DOM中刪除的過程

裝載過程

  • constructor()
  • getInitialState()
  • getDefaultProps()
  • componentWillMount()
  • render()
  • componentDidMount()

constructor()

constructor() 是ES6中每個(gè)類的構(gòu)造函數(shù)癞埠,要?jiǎng)?chuàng)建一個(gè)組件類的實(shí)例订歪,當(dāng)然會(huì)調(diào)用對應(yīng)的構(gòu)造函數(shù)挪丢。
React中分為函數(shù)組件(Functional Component )和類組件(Class Component),劃分依據(jù)是根據(jù)組件的定義方式亮隙。函數(shù)組件使用函數(shù)定義組件摧冀,類組件使用ES6 class定義組件。
函數(shù)組件或者說無狀態(tài)組件(不需要維護(hù)state的組件)不需要定義構(gòu)造函數(shù)梯捕。

一個(gè)React組件需要夠著函數(shù),目的如下:

  • 初始化state窝撵,因?yàn)榻M件生命周期中任何函數(shù)都可能要訪問state傀顾,那么整個(gè)生命周期中第一個(gè)被調(diào)用的構(gòu)造函數(shù)自然是初始化state最理想的地方;
  • 綁定成員函數(shù)的 this 環(huán)境忿族。

在ES6語法下锣笨,類的每個(gè)成員函數(shù)在執(zhí)行時(shí)的this并不是和類的實(shí)例自動(dòng)綁定的。而在構(gòu)造函數(shù)中道批,this就是當(dāng)前組件的實(shí)例错英,所以,為了方便將來的調(diào)用隆豹,往往在構(gòu)造函數(shù)中將這個(gè)實(shí)例的特定函數(shù)綁定this為當(dāng)前實(shí)例椭岩。

getInitialState() and getDefaultProps()

  • getInitialState()
  • getDefaultProps()
    這兩個(gè)函數(shù)只有用React.createClass() 方法創(chuàng)造的組件類才會(huì)發(fā)生作用。在ES6用class語法糖創(chuàng)建的組件類這個(gè)函數(shù)根本不會(huì)產(chǎn)生作用璃赡。
    在ES6中判哥,對應(yīng)的可以使用類屬性來設(shè)置默認(rèn)的props,ClassName.defaultProps = {xx:xx};
    可以直接在構(gòu)造函數(shù)中給state設(shè)置默認(rèn)值碉考。

render()

React組件的父組件React.Component類對除了render()方法之外的生命周期函數(shù)都有默認(rèn)實(shí)現(xiàn)塌计,所以render()函數(shù)必須要自己實(shí)現(xiàn)。
render函數(shù)并不做實(shí)際的渲染動(dòng)作侯谁,它只是返回一個(gè)JSX描述的結(jié)構(gòu)锌仅,最終由React來操作渲染過程。

render()函數(shù)應(yīng)該是一個(gè)純函數(shù)墙贱,完全根據(jù)this.state 和 this.props來決定返回的結(jié)果热芹,而且不產(chǎn)生任何副作用。在render()函數(shù)中調(diào)用 this.setState() 毫無疑問是錯(cuò)誤的惨撇,因?yàn)橐粋€(gè)純函數(shù)不應(yīng)該引起狀態(tài)的改變伊脓。

componentWillMount() 和 componentDidMount()

這兩個(gè)函數(shù)在render前后進(jìn)行調(diào)用。

componentWillMount()發(fā)生在“將要裝載”的時(shí)候魁衙,這個(gè)時(shí)候還沒有任何渲染效果报腔,即使調(diào)用 this.setState修改狀態(tài)也不會(huì)引發(fā)重新繪制株搔,一切都遲了。換句話說纯蛾,所有可以在這個(gè)componentWillMount()中做的事情邪狞,都可以提前到constructor中去做∶┳玻可以認(rèn)為這個(gè)函數(shù)只是為了和componentDidmount對稱

componentDidMount()作用大帆卓,在render函數(shù)被調(diào)用完之后,componentDidMount()并不是會(huì)被立刻調(diào)用米丘,componentDidMount() 被調(diào)用的時(shí)候剑令,render函數(shù)返回的東西已經(jīng)引發(fā)了渲染,組件已經(jīng)被裝載到DOM樹上拄查。

父組件ControlPanel

class ControlPanel extends Component {
  render() {
    return (
      <div style={style}>
        <Counter caption="First"/>
        <Counter caption="Second" initValue={10} />
        <Counter caption="Third" initValue={20} />
        <button onClick={ () => this.forceUpdate() }>
          Click me to re-render!
        </button>
      </div>
    );
  }
}

子組件Counter

class Counter extends Component {

  constructor(props) {
    super(props);

    this.onClickIncrementButton = this.onClickIncrementButton.bind(this);
    this.onClickDecrementButton = this.onClickDecrementButton.bind(this);

    this.state = {
      count: props.initValue
    }
  }
  
  onClickIncrementButton() {
    this.setState({count: this.state.count + 1});
  }

  onClickDecrementButton() {
    this.setState({count: this.state.count - 1});
  }

  
  render() {
    const {caption} = this.props;
    return (
      <div>
        <button style={buttonStyle} onClick={this.onClickIncrementButton}>+</button>
        <button style={buttonStyle} onClick={this.onClickDecrementButton}>-</button>
        <span>{caption} count: {this.state.count}</span>
      </div>
    );
  }
}
頁面第一次渲染.png

componentWillMount() 都是緊貼著自己組件的render函數(shù)之前被調(diào)用吁津,但是componentDidMount() 可不是緊跟著render函數(shù)之后,當(dāng)父組件里面的所有子組件的render函數(shù)都被調(diào)用之后堕扶,子組件的componentDidMount() 才按照子組件的順序連在一起被調(diào)用碍脏。

render函數(shù)本身并不往DOM樹上渲染或者裝載內(nèi)容,它只是返回一個(gè)JSX表示的對象稍算,然后由react庫根據(jù)返回對象決定如何渲染典尾。而React庫肯定要把所有組件返回的結(jié)果綜合起來,才能知道如何產(chǎn)生對應(yīng)的DOM修改糊探。

更新過程

當(dāng)props或者state被修改時(shí)钾埂,會(huì)引發(fā)組件的更新過程。更新過程會(huì)依次調(diào)用下面的生命周期科平,但并不是所有的更新過程都會(huì)執(zhí)行全部函數(shù)褥紫。

  • componentWillReceiveProps()
  • shouldComponentUpdate()
  • componentWillUpdate()
  • render()
  • componentDidUpdate()

componentWillReceiveProps(nextProps)

對于這個(gè)函數(shù),有些地方認(rèn)為這個(gè)函數(shù)只有當(dāng)組件的props發(fā)生改變的時(shí)候才會(huì)被調(diào)用瞪慧,這種說法是錯(cuò)誤的髓考。
實(shí)際上,只要是父組件的render函數(shù)被調(diào)用弃酌,在render函數(shù)里面被渲染的子組件就會(huì)經(jīng)歷更新過程氨菇,不管父組件傳給子組件的props有沒有改變,都會(huì)觸發(fā)子組件的componentWillReceiveProps()函數(shù)矢腻。

但是门驾,注意一點(diǎn)射赛,通過this.setState() 方法觸發(fā)的更新過程不會(huì)調(diào)用這個(gè)函數(shù)多柑,這是因?yàn)檫@個(gè)函數(shù)適合根據(jù)新的props值(也就是nextProps 參數(shù))來計(jì)算出是不是要更新內(nèi)部狀態(tài)state。更新組件內(nèi)部狀態(tài)的方法就是this.setState楣责,如果this.setState()的調(diào)用導(dǎo)致componentWillReceiveProps()再次被調(diào)用竣灌,那就是一個(gè)死循環(huán)聂沙。

click forceUpdate所在的button.png

shouldComponentUpdate(nextProps,nextState)

除了render函數(shù)初嘹,shouldComponentUpdate()可能是React組件生命周期中最重要的一個(gè)函數(shù)了及汉。這兩個(gè)函數(shù)也是React生命周期中兩個(gè)要求有返回結(jié)果的函數(shù)。

  • render函數(shù)決定了該渲染什么屯烦,返回一個(gè)JSX描述的結(jié)構(gòu)坷随,
  • shouldComponentUpdate 函數(shù)決定了一個(gè)組件什么時(shí)候不需要渲染,返回Boolean值驻龟。React默認(rèn)的實(shí)現(xiàn)方式就是簡單的返回true

在更新過程中温眉,React庫首先調(diào)用shouldComponentUpdate函數(shù),如果返回結(jié)果是true翁狐,那么就繼續(xù)更新過程类溢,接下來調(diào)用render函數(shù),如果是false露懒,那么就會(huì)立刻停止更新闯冷,不會(huì)引發(fā)后續(xù)的渲染。所以懈词,使用shouldComponentUpdate函數(shù)可以提高性能蛇耀。

在Counter組件里面加上重寫的shouldComponentUpdate函數(shù),如果nextProps和nextState沒有變化坎弯,那么將不進(jìn)行渲染蒂窒。

  shouldComponentUpdate(nextProps, nextState) {
    return (nextProps.caption !== this.props.caption) ||
           (nextState.count !== this.state.count);
  }

點(diǎn)擊click re-render按鈕后,因?yàn)閺母附M件傳遞的props沒有改變荞怒,而Counter子組件內(nèi)部state也沒有改變洒琢,所以不進(jìn)行渲染,沒有進(jìn)行render方法褐桌。


shouldComponentUpdate.png

componentWillUpdate 和 componentDidUpdate

卸載過程

componentWillUnmount

卸載過程只有這一個(gè)函數(shù)衰抑,適合做一些清理工作。和裝載荧嵌、更新過程不一樣呛踊,這個(gè)函數(shù)沒有配對的Did函數(shù),因?yàn)樾遁d完了就沒有卸載完了再做的事情了啦撮。

參考其他文章

Road to learn React Chinese

React生命周期描述.png

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末谭网,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子赃春,更是在濱河造成了極大的恐慌愉择,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,884評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異锥涕,居然都是意外死亡衷戈,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,347評論 3 385
  • 文/潘曉璐 我一進(jìn)店門层坠,熙熙樓的掌柜王于貴愁眉苦臉地迎上來殖妇,“玉大人,你說我怎么就攤上這事破花∏ぃ” “怎么了?”我有些...
    開封第一講書人閱讀 157,435評論 0 348
  • 文/不壞的土叔 我叫張陵座每,是天一觀的道長蔚润。 經(jīng)常有香客問我,道長尺栖,這世上最難降的妖魔是什么嫡纠? 我笑而不...
    開封第一講書人閱讀 56,509評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮延赌,結(jié)果婚禮上除盏,老公的妹妹穿的比我還像新娘。我一直安慰自己挫以,他們只是感情好者蠕,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,611評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著掐松,像睡著了一般踱侣。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上大磺,一...
    開封第一講書人閱讀 49,837評論 1 290
  • 那天抡句,我揣著相機(jī)與錄音,去河邊找鬼杠愧。 笑死待榔,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的流济。 我是一名探鬼主播锐锣,決...
    沈念sama閱讀 38,987評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼绳瘟!你這毒婦竟也來了雕憔?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,730評論 0 267
  • 序言:老撾萬榮一對情侶失蹤糖声,失蹤者是張志新(化名)和其女友劉穎斤彼,沒想到半個(gè)月后分瘦,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,194評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡畅卓,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,525評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了蟋恬。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片翁潘。...
    茶點(diǎn)故事閱讀 38,664評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖歼争,靈堂內(nèi)的尸體忽然破棺而出拜马,到底是詐尸還是另有隱情,我是刑警寧澤沐绒,帶...
    沈念sama閱讀 34,334評論 4 330
  • 正文 年R本政府宣布俩莽,位于F島的核電站,受9級特大地震影響乔遮,放射性物質(zhì)發(fā)生泄漏扮超。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,944評論 3 313
  • 文/蒙蒙 一蹋肮、第九天 我趴在偏房一處隱蔽的房頂上張望出刷。 院中可真熱鬧,春花似錦坯辩、人聲如沸馁龟。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,764評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽坷檩。三九已至,卻和暖如春改抡,著一層夾襖步出監(jiān)牢的瞬間矢炼,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,997評論 1 266
  • 我被黑心中介騙來泰國打工阿纤, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留裸删,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,389評論 2 360
  • 正文 我出身青樓阵赠,卻偏偏與公主長得像涯塔,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子清蚀,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,554評論 2 349

推薦閱讀更多精彩內(nèi)容