React 組件的生命周期

React 組件的一生,是光榮的一生,是革命的一生,在它的一生中會經(jīng)歷這樣幾個階段:

  • 裝載階段
  • 更新階段
  • 銷毀階段

每一階段都會觸發(fā)相應(yīng)的生命周期函數(shù),下面依次來說一說這些生命周期函數(shù)。

裝載階段

裝載階段就是組件第一次被渲染時的階段,這一階段相關(guān)的生命周期函數(shù)有:

  • constructor
  • componentWillMount
  • render
  • componentDidMount

下面是這些方法的一些說明:
constructor:用來初始化組件,獲取組件的初始屬性(props)或狀態(tài)(state),其作用類似于 ES5 createClass 寫法中的 getInitialState 和 getDefaultProps 函數(shù)。
componentWillMount:在組件即將裝載前調(diào)用。
render:用來生成一個 JSX 描述結(jié)構(gòu),告訴 React 本次要裝載哪些東西,需要注意的是,render方法只用來返回一個 JSX 結(jié)構(gòu),并不負(fù)責(zé)裝載,具體的裝載工作由 React 完成。
componentDidMount:在組件被裝載之后調(diào)用,此時已經(jīng)完成了 DOM 更新,組件已經(jīng)被裝載到真實(shí)的 DOM 樹中了,可以進(jìn)行相應(yīng)的 DOM 操作,比如添加原生的 DOM 事件就應(yīng)該放在 componentDidMount 中進(jìn)行。
看一個例子:

import React,{ Component } from "react";
import "./App.css";

export default class App extends Component{
    constructor(props){
        super(props);
        console.log("constructor")
    }

    componentWillMount() {
        console.log("componentWillMount")
    }

    componentDidMount(){
        console.log("componentDidMount")
    }

    render(){
        console.log("render")
        return(
            <div className = "App-div">
                
            </div>
        );
    }
}

打開瀏覽器,控制臺中輸出的結(jié)果為:

constructor
componentWillMount
render
componentDidMount

多個組件的情況

如果 App 組件中渲染了其他的組件,那么這些組件的生命周期函數(shù)是怎樣調(diào)用的呢?
新建一個 SubComponent.js:

import React,{ Component } from "react";

export default class Sub extends Component{
    constructor(props){
        super(props);
        console.log("constructor")
    }

    componentWillMount() {
        console.log("componentWillMount")
    }

    componentDidMount(){
        console.log("componentDidMount")
    }

    render(){
        console.log("render")
        return(
            <div>我是子組件</div>
        );
    }
}

修改 App.js,讓其渲染兩個子組件:

import React,{ Component } from "react";
import Sub from "./SubComponent.js";
import "./App.css";

export default class App extends Component{
    
    render(){
        const SubArr = [1,2].map((v)=>{
            return <Sub key = {v} />
        });

        return(
            <div className = "App-div">
                { SubArr }
            </div>
        );
    }
}

打開瀏覽器,看下控制臺中的輸出:

constructor
componentWillMount
render
constructor
componentWillMount
render
componentDidMount
componentDidMount

這兩個子組件的 componentDidMount 函數(shù)并不是在 render 函數(shù)之后執(zhí)行,而是放在最后執(zhí)行了,為什么呢?
還是回到上面那句話:render 函數(shù)只用來生成 JSX 組件結(jié)構(gòu),不負(fù)責(zé)裝載工作,具體的狀態(tài)工作交個 React 完成
React 需要在形成完整的 JSX 結(jié)構(gòu)之后才進(jìn)行裝載,也就是說,要在兩個 render 函數(shù)都調(diào)用完成后才進(jìn)行裝載工作,而后再調(diào)用 componentDidMount 生命周期函數(shù)。

更新階段

如果組件中的 state 或者 props 發(fā)生了改變,React 就會更新該組件,此時會調(diào)用更新階段中相關(guān)的生命周期函數(shù):

  • componentWillReceiveProps
  • shouldComponentUpdate
  • componentWillUpdate
  • render
  • componentDidUpdate

componentWillReceiveProps 函數(shù)在傳遞給子組件的 props 變化或者父組件更新時調(diào)用。
修改 SubComponent.js:

import React,{ Component } from "react";

export default class Sub extends Component{
    componentWillReceiveProps(nextProps) {
        console.log("componentWillReceiveProps");
    }

    shouldComponentUpdate(nextProps, nextState) {
        console.log("shouldComponentUpdate");
        return true;
    }

    componentDidUpdate(prevProps, prevState) {
        console.log("componentDidUpdate");
    }

    render(){
        console.log("render")
        return(
            <div>我是子組件</div>
        );
    }
}

修改 App.js,增加一個按鈕,點(diǎn)擊時強(qiáng)制更新:

import React,{ Component } from "react";
import Sub from "./SubComponent.js";
import "./App.css";

export default class App extends Component{

    render(){
        const SubArr = [1,2].map((v)=>{
            return <Sub key = {v} />
        });

        return(
            <div className = "App-div">
                <button onClick = { ()=>this.forceUpdate() }>點(diǎn)擊強(qiáng)制更新</button>
                { SubArr }
            </div>
        );
    }
}

點(diǎn)擊更新按鈕,看下控制臺的輸出:

componentWillReceiveProps
shouldComponentUpdate
render
componentWillReceiveProps
shouldComponentUpdate
render
componentDidUpdate
componentDidUpdate

可見,父組件的更新也會引起子組件的更新,如果父組件中有很多子組件,默認(rèn)情況下,在父組件進(jìn)行更新(通常是父組件的 props 或 state 發(fā)生變化)或者父組件傳遞給子組件的 props 發(fā)生變化時,會引起所有子組件的更新。如果子組件數(shù)量眾多,功能復(fù)雜,那么進(jìn)行更新會產(chǎn)生大量的性能浪費(fèi),即使是在使用 Virtual DOM 的情況下。針對這種情況,我們就需要使用下面介紹的 shouldComponentUpdate 函數(shù)了。
P.S.在使用 setState 時并不會調(diào)用 componentWillReceiveProps,而是直接調(diào)用 shouldComponentUpdate 函數(shù)。

shouldComponentUpdate 函數(shù)接受兩個參數(shù):nextProps 和 nextState,分別表示引發(fā)本次組件更新的 props 或 state,該函數(shù)的返回值的真假決定組件是否更新,默認(rèn)返回 true。實(shí)際應(yīng)用場景中,我們可以將這兩個參數(shù)和組件當(dāng)前的 props(this.props)和當(dāng)前的 state(this.state)進(jìn)行比對,以決定是否更新組件,提高性能。
為了方便演示,給每個子組件傳遞一個名為 flag 的 prop:

import React,{ Component } from "react";
import Sub from "./SubComponent.js";
import "./App.css";

export default class App extends Component{

    render(){
        const SubArr = [1,2].map((v)=>{
            return <Sub key = {v} flag = "1" />
        });

        return(
            <div className = "App-div">
                <button onClick = { ()=>this.forceUpdate() }>點(diǎn)擊強(qiáng)制更新</button>
                { SubArr }
            </div>
        );
    }
}

修改 SubComponent.js:

import React,{ Component } from "react";

export default class Sub extends Component{
    componentWillReceiveProps(nextProps) {
        console.log("componentWillReceiveProps");
    }

    shouldComponentUpdate(nextProps, nextState) {
        return (nextProps.flag !== this.props.flag);
    }

    componentDidUpdate(prevProps, prevState) {
        console.log("componentDidUpdate");
    }

    render(){
        console.log("render")
        return(
            <div>我是子組件</div>
        );
    }
}

控制臺的輸出結(jié)果為:

componentWillReceiveProps
componentWillReceiveProps

父組件更新后,會引起子組件的更新,首先就是調(diào)用 componentWillReceiveProps 方法,之后在 shouldComponentUpdate 中進(jìn)行屬性值的判斷,由于兩次渲染都傳遞了相同的屬性值,因此沒有必要更新組件,shouldComponentUpdate 函數(shù)返回 false,后面的一系列生命周期函數(shù)就不執(zhí)行了,提高了渲染性能。
componentWillUpdate 函數(shù)在組件即將更新時調(diào)用。
render 函數(shù)用來產(chǎn)出本次更新的 JSX 組件樹結(jié)構(gòu)。
componentDidUpdate 函數(shù)在組件完成更新后調(diào)用。當(dāng)組件被更新時,會重新繪制 DOM 樹。同 componentDidMount 函數(shù),該函數(shù)并不是在每個子組件 render 方法執(zhí)行后立即被執(zhí)行的,而是等待 DOM 樹更新后再執(zhí)行。

卸載過程

卸載過程就一個函數(shù):

  • componentWillUnmount

該函數(shù)用來做一些清理工作,比如如果在組件中使用了原生的 DOM 事件,需要在組件被銷毀前移除該事件,防止內(nèi)存泄露,或者清理定時器等。

完。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 組件的生命周期 組件在react的生命周期中主要經(jīng)歷三個階段:實(shí)例化、存在期和銷毀時。React.js在組件生命周...
    落花的季節(jié)閱讀 676評論 0 2
  • React組件生命周期4個階段:創(chuàng)建階段、實(shí)例化階段、更新階段、銷毀階段 【創(chuàng)建階段】● getDefaultPr...
    mayunyun閱讀 281評論 0 0
  • 一般來說,一個組件類由 extends Component 創(chuàng)建,并且提供一個 render 方法以及其他可選的生...
    ElineC閱讀 674評論 0 2
  • 006@React組件的生命周期.md React Native 是基于組件化開發(fā)。弄清楚組件的生命周期對于我們開...
    驀然之間的閱讀 504評論 1 0
  • 理解React組件的生命周期 本文作者寫作的時間較早,所以里面會出現(xiàn)很多的舊版ES5的時代的方法。不過,雖然如此并...
    uncle_charlie閱讀 1,674評論 0 2

友情鏈接更多精彩內(nèi)容