React:組件的生命周期

在組件的整個(gè)生命周期中,隨著該組件的props或者state發(fā)生改變,其DOM表現(xiàn)也會(huì)有相應(yīng)的變化。一個(gè)組件就是一個(gè)狀態(tài)機(jī),對于特定地輸入,它總返回一致的輸出。

一個(gè)React組件的生命周期分為三個(gè)部分:實(shí)例化、存在期和銷毀時(shí)。

實(shí)例化

當(dāng)組件在客戶端被實(shí)例化,第一次被創(chuàng)建時(shí),以下方法依次被調(diào)用:

1、getDefaultProps
2、getInitialState
3、componentWillMount
4、render
5、componentDidMount

當(dāng)組件在服務(wù)端被實(shí)例化,首次被創(chuàng)建時(shí),以下方法依次被調(diào)用:

1、getDefaultProps
2、getInitialState
3、componentWillMount
4、render

componentDidMount 不會(huì)在服務(wù)端被渲染的過程中調(diào)用。

getDefaultProps

對于每個(gè)組件實(shí)例來講,這個(gè)方法只會(huì)調(diào)用一次,該組件類的所有后續(xù)應(yīng)用,getDefaultPops 將不會(huì)再被調(diào)用,其返回的對象可以用于設(shè)置默認(rèn)的 props(properties的縮寫) 值。

var Hello = React.creatClass({
    getDefaultProps: function(){
        return {
            name: 'pomy',
            git: 'dwqs'
        }
    },
    
    render: function(){
        return (
            <div>Hello,{this.props.name},git username is {this.props.dwqs}</div>
        )
    }
});

ReactDOM.render(<Hello />, document.body);

也可以在掛載組件的時(shí)候設(shè)置 props:

var data = [{title: 'Hello'}];
<Hello data={data} />

或者調(diào)用 setProps (一般不需要調(diào)用)來設(shè)置其 props:

var data = [{title: 'Hello'}];
var Hello = React.render(<Demo />, document.body);
Hello.setProps({data:data});
但只能在子組件或組件樹上調(diào)用 setProps。別調(diào)用 this.setProps 或者 直接修改 this.props。將其當(dāng)做只讀數(shù)據(jù)。

React通過 propTypes 提供了一種驗(yàn)證 props 的方式,propTypes 是一個(gè)配置對象,用于定義屬性類型:

var survey = React.createClass({
    propTypes: {
        survey: React.PropTypes.shape({
            id: React.PropTypes.number.isRequired
        }).isRequired,
        onClick: React.PropTypes.func,
        name: React.PropTypes.string,
        score: React.PropTypes.array
        ...
    },
    
    //...
})

組件初始化時(shí),如果傳遞的屬性和 propTypes 不匹配,則會(huì)打印一個(gè) console.warn 日志。如果是可選配置,可以去掉.isRequired。常用的 PropTypes 如下:

getInitialState

對于組件的每個(gè)實(shí)例來說,這個(gè)方法的調(diào)用有且只有一次,用來初始化每個(gè)實(shí)例的 state,在這個(gè)方法里,可以訪問組件的 props。每一個(gè)React組件都有自己的 state,其與 props 的區(qū)別在于 state只存在組件的內(nèi)部,props 在所有實(shí)例中共享。

getInitialState 和 getDefaultPops 的調(diào)用是有區(qū)別的,getDefaultPops 是對于組件類來說只調(diào)用一次,后續(xù)該類的應(yīng)用都不會(huì)被調(diào)用,而 getInitialState 是對于每個(gè)組件實(shí)例來講都會(huì)調(diào)用,并且只調(diào)一次

var LikeButton = React.createClass({
  getInitialState: function() {
    return {liked: false};
  },
  handleClick: function(event) {
    this.setState({liked: !this.state.liked});
  },
  render: function() {
    var text = this.state.liked ? 'like' : 'haven\'t liked';
    return (
      <p onClick={this.handleClick}>
        You {text} this. Click to toggle.
      </p>
    );
  }
});

ReactDOM.render(
  <LikeButton />,
  document.getElementById('example')
);

每次修改 state,都會(huì)重新渲染組件,實(shí)例化后通過 state 更新組件,會(huì)依次調(diào)用下列方法:
1、shouldComponentUpdate
2、componentWillUpdate
3、render
4、componentDidUpdate

但是不要直接修改 this.state,要通過 this.setState 方法來修改。

componentWillMount

該方法在首次渲染之前調(diào)用,也是再 render 方法調(diào)用之前修改 state 的最后一次機(jī)會(huì)。

render

該方法會(huì)創(chuàng)建一個(gè)虛擬DOM,用來表示組件的輸出。對于一個(gè)組件來講,render方法是唯一一個(gè)必需的方法。render方法需要滿足下面幾點(diǎn):

1.只能通過 this.props 和 this.state 訪問數(shù)據(jù)(不能修改)
2.可以返回 null,false 或者任何React組件
3.只能出現(xiàn)一個(gè)頂級組件,不能返回一組元素
4.不能改變組件的狀態(tài)
5.不能修改DOM的輸出

render方法返回的結(jié)果并不是真正的DOM元素,而是一個(gè)虛擬的表現(xiàn),類似于一個(gè)DOM tree的結(jié)構(gòu)的對象。react之所以效率高,就是這個(gè)原因。

componentDidMount

該方法不會(huì)在服務(wù)端被渲染的過程中調(diào)用。該方法被調(diào)用時(shí),已經(jīng)渲染出真實(shí)的 DOM,可以再該方法中通過 this.getDOMNode() 訪問到真實(shí)的 DOM(推薦使用 ReactDOM.findDOMNode())。

var data = [..];
var comp = React.createClass({
    render: function(){
        return <imput .. />
    },
    componentDidMount: function(){
        $(this.getDOMNode()).autoComplete({
            src: data
        })
    }
})

由于組件并不是真實(shí)的 DOM 節(jié)點(diǎn),而是存在于內(nèi)存之中的一種數(shù)據(jù)結(jié)構(gòu),叫做虛擬 DOM (virtual DOM)。只有當(dāng)它插入文檔以后,才會(huì)變成真實(shí)的 DOM 。有時(shí)需要從組件獲取真實(shí) DOM 的節(jié)點(diǎn),這時(shí)就要用到 ref 屬性:

var Area = React.createClass({
    render: function(){
        this.getDOMNode(); //render調(diào)用時(shí),組件未掛載,這里將報(bào)錯(cuò)
        
        return <canvas ref='mainCanvas'>
    },
    componentDidMount: function(){
        var canvas = this.refs.mainCanvas.getDOMNode();
        //這是有效的,可以訪問到 Canvas 節(jié)點(diǎn)
    }
})

需要注意的是,由于 this.refs.[refName] 屬性獲取的是真實(shí) DOM ,所以必須等到虛擬 DOM 插入文檔以后,才能使用這個(gè)屬性,否則會(huì)報(bào)錯(cuò)。

存在期

此時(shí)組件已經(jīng)渲染好并且用戶可以與它進(jìn)行交互,比如鼠標(biāo)點(diǎn)擊,手指點(diǎn)按,或者其它的一些事件,導(dǎo)致應(yīng)用狀態(tài)的改變,你將會(huì)看到下面的方法依次被調(diào)用

1、componentWillReceiveProps
2、shouldComponentUpdate
3、componentWillUpdate
4、render
5、componentDidUpdate

componentWillReceiveProps

組件的 props 屬性可以通過父組件來更改,這時(shí),componentWillReceiveProps 將來被調(diào)用??梢栽谶@個(gè)方法里更新 state,以觸發(fā) render 方法重新渲染組件。

componentWillReceiveProps: function(nextProps){
    if(nextProps.checked !== undefined){
        this.setState({
            checked: nextProps.checked
        })
    }
}

shouldComponentUpdate

如果你確定組件的 props 或者 state 的改變不需要重新渲染,可以通過在這個(gè)方法里通過返回 false 來阻止組件的重新渲染,返回 `false 則不會(huì)執(zhí)行 render 以及后面的 componentWillUpdate,componentDidUpdate 方法。

該方法是非必須的,并且大多數(shù)情況下沒有在開發(fā)中使用。

shouldComponentUpdate: function(nextProps, nextState){
    return this.state.checked === nextState.checked;
    //return false 則不更新組件
}

componentWillUpdate

這個(gè)方法和 componentWillMount 類似,在組件接收到了新的 props 或者 state 即將進(jìn)行重新渲染前,componentWillUpdate(object nextProps, object nextState) 會(huì)被調(diào)用,注意不要在此方面里再去更新 props 或者 state。

銷毀時(shí)

componentWillUnmount

每當(dāng)React使用完一個(gè)組件,這個(gè)組件必須從 DOM 中卸載后被銷毀,此時(shí) componentWillUnmout 會(huì)被執(zhí)行,完成所有的清理和銷毀工作,在 componentDidMount 中添加的任務(wù)都需要再該方法中撤銷,如創(chuàng)建的定時(shí)器或事件監(jiān)聽器。

當(dāng)再次裝載組件時(shí),以下方法會(huì)被依次調(diào)用:

1、getInitialState
2、componentWillMount
3、render
4、componentDidMount

反模式

在 getInitialState 方法中,嘗試通過 this.props 來創(chuàng)建 state 的做法是一種反模式。

//反模式
getDefaultProps: function(){
    return {
        data: new Date()
    }
},
getInitialState: function(){
    return {
        day: this.props.date - new Date()
    }
},
render: function(){
    return <div>Day:{this.state.day}</div>
}

經(jīng)過計(jì)算后的值不應(yīng)該賦給 state,正確的模式應(yīng)該是在渲染時(shí)計(jì)算這些值。這樣保證了計(jì)算后的值永遠(yuǎn)不會(huì)與派生出它的 props 值不同步。

//正確模式
getDefaultProps: function(){
    return {
        data: new Date()
    }
},
render: function(){
    var day = this.props.date - new Date();
    return <div>Day:{day}</div>
}

如果只是簡單的初始化 state,那么應(yīng)用反模式是沒有問題的。

總結(jié)

以下面的一張圖總結(jié)組件的生命周期:

image.png

原文:http://www.ido321.com/1653.html

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

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

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