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ù)端被渲染的過程中調(diào)用唬渗。

getDefaultProps

對(duì)于每個(gè)組件實(shí)例來講典阵,這個(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)用)來設(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è)配置對(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í)例來說司志,這個(gè)方法的調(diào)用有且只有一次甜紫,用來初始化每個(gè)實(shí)例的 state,在這個(gè)方法里骂远,可以訪問組件的 props囚霸。每一個(gè)React組件都有自己的 state,其與 props 的區(qū)別在于 state只存在組件的內(nèi)部激才,props 在所有實(shí)例中共享拓型。

getInitialState 和 getDefaultPops 的調(diào)用是有區(qū)別的,getDefaultPops 是對(duì)于組件類來說只調(diào)用一次瘸恼,后續(xù)該類的應(yīng)用都不會(huì)被調(diào)用劣挫,而 getInitialState 是對(duì)于每個(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狼钮,用來表示組件的輸出碳柱。對(duì)于一個(gè)組件來講,render方法是唯一一個(gè)必需的方法熬芜。render方法需要滿足下面幾點(diǎn):

1.只能通過 this.props 和 this.state 訪問數(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ù)端被渲染的過程中調(diào)用半火。該方法被調(diào)用時(shí),已經(jīng)渲染出真實(shí)的 DOM季俩,可以再該方法中通過 this.getDOMNode() 訪問到真實(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();
        //這是有效的秩伞,可以訪問到 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抬探。

componentDidUpdate

這個(gè)方法和 componentDidMount 類似,在組件重新被渲染之后帆赢,componentDidUpdate(object prevProps, object prevState) 會(huì)被調(diào)用小压∠吖#可以在這里訪問并修改 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 方法中,嘗試通過 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
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末鳄抒,一起剝皮案震驚了整個(gè)濱河市闯捎,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌许溅,老刑警劉巖瓤鼻,帶你破解...
    沈念sama閱讀 219,110評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異贤重,居然都是意外死亡茬祷,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,443評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門游桩,熙熙樓的掌柜王于貴愁眉苦臉地迎上來牲迫,“玉大人,你說我怎么就攤上這事借卧№镌鳎” “怎么了?”我有些...
    開封第一講書人閱讀 165,474評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵铐刘,是天一觀的道長陪每。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么檩禾? 我笑而不...
    開封第一講書人閱讀 58,881評(píng)論 1 295
  • 正文 為了忘掉前任挂签,我火速辦了婚禮,結(jié)果婚禮上盼产,老公的妹妹穿的比我還像新娘饵婆。我一直安慰自己,他們只是感情好戏售,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,902評(píng)論 6 392
  • 文/花漫 我一把揭開白布侨核。 她就那樣靜靜地躺著,像睡著了一般灌灾。 火紅的嫁衣襯著肌膚如雪搓译。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,698評(píng)論 1 305
  • 那天锋喜,我揣著相機(jī)與錄音些己,去河邊找鬼。 笑死嘿般,一個(gè)胖子當(dāng)著我的面吹牛段标,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播炉奴,決...
    沈念sama閱讀 40,418評(píng)論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼怀樟,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了盆佣?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,332評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤械荷,失蹤者是張志新(化名)和其女友劉穎共耍,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體吨瞎,經(jīng)...
    沈念sama閱讀 45,796評(píng)論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡痹兜,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,968評(píng)論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了颤诀。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片字旭。...
    茶點(diǎn)故事閱讀 40,110評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖崖叫,靈堂內(nèi)的尸體忽然破棺而出遗淳,到底是詐尸還是另有隱情,我是刑警寧澤心傀,帶...
    沈念sama閱讀 35,792評(píng)論 5 346
  • 正文 年R本政府宣布屈暗,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏养叛。R本人自食惡果不足惜种呐,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,455評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望弃甥。 院中可真熱鬧爽室,春花似錦、人聲如沸淆攻。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,003評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽卜录。三九已至戈擒,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間艰毒,已是汗流浹背筐高。 一陣腳步聲響...
    開封第一講書人閱讀 33,130評(píng)論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留丑瞧,地道東北人柑土。 一個(gè)月前我還...
    沈念sama閱讀 48,348評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像绊汹,于是被迫代替她去往敵國和親稽屏。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,047評(píng)論 2 355

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