React:組建的生命周期

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

一個(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ù)端被渲染的過(guò)程中調(diào)用萎河。

getDefaultProps

對(duì)于每個(gè)組件實(shí)例來(lái)講,這個(gè)方法只會(huì)調(diào)用一次,該組件類的所有后續(xù)應(yīng)用虐杯,getDefaultPops 將不會(huì)再被調(diào)用玛歌,其返回的對(duì)象可以用于設(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)用)來(lái)設(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通過(guò) propTypes 提供了一種驗(yàn)證 props 的方式达舒,propTypes 是一個(gè)配置對(duì)象值朋,用于定義屬性類型:

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 如下:
https://segmentfault.com/img/remote/1460000004840554/view

getInitialState

對(duì)于組件的每個(gè)實(shí)例來(lái)說(shuō)篙骡,這個(gè)方法的調(diào)用有且只有一次,用來(lái)初始化每個(gè)實(shí)例的 state丈甸,在這個(gè)方法里糯俗,可以訪問(wèn)組件的 props。每一個(gè)React組件都有自己的 state睦擂,其與 props 的區(qū)別在于 state只存在組件的內(nèi)部得湘,props 在所有實(shí)例中共享。

getInitialState 和 getDefaultPops 的調(diào)用是有區(qū)別的顿仇,getDefaultPops 是對(duì)于組件類來(lái)說(shuō)只調(diào)用一次淘正,后續(xù)該類的應(yīng)用都不會(huì)被調(diào)用,而 getInitialState 是對(duì)于每個(gè)組件實(shí)例來(lái)講都會(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í)例化后通過(guò) state 更新組件惩淳,會(huì)依次調(diào)用下列方法:

1、shouldComponentUpdate
2乓搬、componentWillUpdate
3思犁、render
4、componentDidUpdate

但是不要直接修改 this.state进肯,要通過(guò) this.setState 方法來(lái)修改激蹲。

componentWillMount

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

render

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

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

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

componentDidMount

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

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();
        //這是有效的,可以訪問(wèn)到 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 屬性可以通過(guò)父組件來(lái)更改淘钟,這時(shí)宦赠,componentWillReceiveProps 將來(lái)被調(diào)用。可以在這個(gè)方法里更新 state,以觸發(fā) render 方法重新渲染組件勾扭。

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

shouldComponentUpdate

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

該方法是非必須的,并且大多數(shù)情況下沒(méi)有在開發(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号俐。

componentDidUpdate

這個(gè)方法和 componentDidMount 類似,在組件重新被渲染之后定庵,componentDidUpdate(object prevProps, object prevState) 會(huì)被調(diào)用吏饿。可以在這里訪問(wèn)并修改 DOM蔬浙。

銷毀時(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 方法中咱揍,嘗試通過(guò) this.props 來(lái)創(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)過(guò)計(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>
}

如果只是簡(jiǎn)單的初始化 state,那么應(yīng)用反模式是沒(méi)有問(wèn)題的硼砰。

總結(jié)

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

image
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末且蓬,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子题翰,更是在濱河造成了極大的恐慌恶阴,老刑警劉巖诈胜,帶你破解...
    沈念sama閱讀 219,427評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異冯事,居然都是意外死亡焦匈,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,551評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門昵仅,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)括授,“玉大人,你說(shuō)我怎么就攤上這事岩饼。” “怎么了囊颅?”我有些...
    開封第一講書人閱讀 165,747評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵皮璧,是天一觀的道長(zhǎng)逾一。 經(jīng)常有香客問(wèn)我,道長(zhǎng)寞冯,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,939評(píng)論 1 295
  • 正文 為了忘掉前任晚伙,我火速辦了婚禮吮龄,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘咆疗。我一直安慰自己漓帚,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,955評(píng)論 6 392
  • 文/花漫 我一把揭開白布午磁。 她就那樣靜靜地躺著尝抖,像睡著了一般。 火紅的嫁衣襯著肌膚如雪迅皇。 梳的紋絲不亂的頭發(fā)上昧辽,一...
    開封第一講書人閱讀 51,737評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音登颓,去河邊找鬼搅荞。 笑死,一個(gè)胖子當(dāng)著我的面吹牛框咙,可吹牛的內(nèi)容都是我干的咕痛。 我是一名探鬼主播,決...
    沈念sama閱讀 40,448評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼喇嘱,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼暇检!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起婉称,我...
    開封第一講書人閱讀 39,352評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤块仆,失蹤者是張志新(化名)和其女友劉穎构蹬,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體悔据,經(jīng)...
    沈念sama閱讀 45,834評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡庄敛,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,992評(píng)論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了科汗。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片藻烤。...
    茶點(diǎn)故事閱讀 40,133評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖头滔,靈堂內(nèi)的尸體忽然破棺而出怖亭,到底是詐尸還是另有隱情,我是刑警寧澤坤检,帶...
    沈念sama閱讀 35,815評(píng)論 5 346
  • 正文 年R本政府宣布兴猩,位于F島的核電站,受9級(jí)特大地震影響早歇,放射性物質(zhì)發(fā)生泄漏倾芝。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,477評(píng)論 3 331
  • 文/蒙蒙 一箭跳、第九天 我趴在偏房一處隱蔽的房頂上張望晨另。 院中可真熱鬧,春花似錦谱姓、人聲如沸借尿。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,022評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)垛玻。三九已至,卻和暖如春奶躯,著一層夾襖步出監(jiān)牢的瞬間帚桩,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,147評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工嘹黔, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留账嚎,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,398評(píng)論 3 373
  • 正文 我出身青樓儡蔓,卻偏偏與公主長(zhǎng)得像郭蕉,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子喂江,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,077評(píng)論 2 355

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

  • React:組件的生命周期 在組件的整個(gè)生命周期中召锈,隨著該組件的props或者state發(fā)生改變,其DOM表現(xiàn)也會(huì)...
    一個(gè)凡人_bfc1閱讀 77評(píng)論 0 0
  • 在組件的整個(gè)生命周期中获询,隨著該組件的props或者state發(fā)生改變涨岁,其DOM表現(xiàn)也會(huì)有相應(yīng)的變化拐袜。一個(gè)組件就是一...
    仲商廿三閱讀 360評(píng)論 0 1
  • 作為一個(gè)合格的開發(fā)者,不要只滿足于編寫了可以運(yùn)行的代碼梢薪。而要了解代碼背后的工作原理蹬铺;不要只滿足于自己的程序...
    六個(gè)周閱讀 8,449評(píng)論 1 33
  • 40、React 什么是React秉撇?React 是一個(gè)用于構(gòu)建用戶界面的框架(采用的是MVC模式):集中處理VIE...
    萌妹撒閱讀 1,017評(píng)論 0 1
  • react的生命周期(二) 前面已經(jīng)詳細(xì)講解過(guò)react的生命周期甜攀,具體可以參考我的另一篇文章:https://w...
    龍波帝國(guó)閱讀 227評(píng)論 0 0