成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

【譯】React 組件的生命周期

Crazy_Coder / 3137人閱讀

摘要:此篇文章我們將會(huì)繼續(xù)探索組件的特性,特別是生命周期。這些方法叫做組件的生命周期方法且會(huì)根據(jù)特定并可預(yù)測(cè)的順序被調(diào)用。基本上所有的組件的生命周期方法都可以被分割成四個(gè)階段初始化掛載階段更新階段卸載階段。

原文:https://medium.com/react-ecosystem/react-components-lifecycle-ce09239010df#.j7h6w8ccc

譯者序:React組件生命周期有很多文章介紹了,這篇作者列出了很多開發(fā)中可能不會(huì)注意的細(xì)節(jié),比如哪些階段執(zhí)行setState是否會(huì)導(dǎo)致render等,對(duì)React組件性能優(yōu)化有一定的幫助,故譯之,不當(dāng)之處敬請(qǐng)指正!

github issue: https://github.com/chemdemo/c...

一段探索React自建內(nèi)部構(gòu)造的旅程

在先前的文章里我們涵蓋了React基本原理和如何構(gòu)建更加復(fù)雜的交互組件。此篇文章我們將會(huì)繼續(xù)探索React組件的特性,特別是生命周期。

稍微思考一下React組件所做的事,首先想到的是一點(diǎn)是:React描述了如何去渲染(DOM)。我們已經(jīng)知道React使用render()方法來達(dá)到這個(gè)目的。然而僅有render()方法可能不一定都能滿足我們的需求。如果在組件rendered之前或之后我們需要做些額外的事情該怎么做呢?我們需要做些什么以避免重復(fù)渲染(re-render)呢?

看起來我們需要對(duì)組件(運(yùn)行)的各個(gè)階段進(jìn)行控制,組件運(yùn)行所有涉及的各個(gè)階段叫做組件的生命周期,并且每一個(gè)React組件都會(huì)經(jīng)歷這些階段。React提供了一些方法并在組件處于相應(yīng)的階段時(shí)通知我們。這些方法叫做React組件的生命周期方法且會(huì)根據(jù)特定并可預(yù)測(cè)的順序被調(diào)用。

基本上所有的React組件的生命周期方法都可以被分割成四個(gè)階段:初始化、掛載階段(mounting)更新階段、卸載階段(unmounting)。讓我們來近距離分別研究下各個(gè)階段。

初始化階段

初始化階段就是我們分別通過getDefaultProps()getInitialState()方法定義this.props默認(rèn)值和this.state初始值的階段。

getDefaultProps()方法被調(diào)用一次并緩存起來——在多個(gè)類實(shí)例之間共享。在組件的任何實(shí)例被創(chuàng)建之前,我們(的代碼邏輯)不能依賴這里的this.props。這個(gè)方法返回一個(gè)對(duì)象并且屬性如果沒有通過父組件傳入的話相應(yīng)的屬性會(huì)掛載到this.props對(duì)象上。

getInitialState()方法也只會(huì)被調(diào)用一次,(調(diào)用時(shí)機(jī))剛好是mounting階段開始之前。返回值將會(huì)被當(dāng)成this.state的初始值,且必須是一個(gè)對(duì)象。

現(xiàn)在我們來證明上面的猜想,實(shí)現(xiàn)一個(gè)顯示的值可以被增加和減少的組件,基本上就是一個(gè)擁有“+”和“-”按鈕的計(jì)數(shù)器。

var Counter = React.createClass({
    getDefaultProps: function() {
        console.log("getDefaultProps");
        return {
            title: "Basic counter!!!"
        }
    },

    getInitialState: function() {
        console.log("getInitialState");
        return {
            count: 0
        }
    },

    render: function() {
        console.log("render");
        return (
            

{this.props.title}

{this.state.count}
); }, handleIncrement: function() { var newCount = this.state.count + 1; this.setState({count: newCount}); }, handleDecrement: function() { var newCount = this.state.count - 1; this.setState({count: newCount}); }, propTypes: { title: React.PropTypes.string } }); ReactDOM.render( React.createElement(Counter), document.getElementById("app-container") );

我們通過getDefaultProps()方法配置一個(gè)“title”屬性,如果沒有傳入則提供一個(gè)默認(rèn)值。然后通過getInitialState()為組件設(shè)置一個(gè)初始state值“{count: 0}”。如果運(yùn)行這段代碼你將會(huì)看到控制臺(tái)輸出如下結(jié)果:

現(xiàn)在我們想要讓Counter組件可以設(shè)置this.state.count初始值和增加/減少的步長值,但依然提供一個(gè)默認(rèn)值:

var Component = React.createClass({
    getDefaultProps: function() {
        console.log("getDefaultProps");
        return {
            title: "Basic counter!!!",
            step: 1
        }
    },

    getInitialState: function() {
        console.log("getInitialState");
        return {
            count: (this.props.initialCount || 0)
        };
    },

    render: function() {
        console.log("render");
        var step = this.props.step;

        return (
            

{this.props.title}

{this.state.count}
); }, updateCounter: function(value) { var newCount = this.state.count + value; this.setState({count: newCount}); }, propTypes: { title: React.PropTypes.string, initialCount: React.PropTypes.number, step: React.PropTypes.number } }); ReactDOM.render( React.createElement(Component, {initialCount: 5, step: 2}), document.getElementById("app-container") );

這里通過Function.prototype.bind使用偏函數(shù)應(yīng)用(Partial Application)來達(dá)到復(fù)用代碼的目的。

現(xiàn)在我們擁有了一個(gè)可定制化的組件。

增長(Mounting)階段

Mounting階段發(fā)生在組件即將被插入到DOM之前。這個(gè)階段有兩個(gè)方法可以用:componentWillMount()componentDidMount()。

componentWillMount()方法是這個(gè)階段最先調(diào)用的,它只在剛好初始渲染(initial rendering)發(fā)生之前被調(diào)用一次,也就是React在DOM插入組件之前。需要注意的是在此處調(diào)用this.setState()方法將不會(huì)觸發(fā)重復(fù)渲染(re-render)。如果添加下面的代碼到計(jì)數(shù)器組件我們將會(huì)看到此方法在getInitialState()之后且render()之前被調(diào)用。

getInitialState: function() {...},
componentWillMount: function() {
    console.log("componentWillMount");
},

componentDidMount()是這個(gè)階段第二個(gè)被調(diào)用的方法,剛好發(fā)生在React插入組件到DOM之后,且也只被調(diào)用一次?,F(xiàn)在可以更新DOM元素了,這意味著這個(gè)方法是初始化其他需要訪問DOM或操作數(shù)據(jù)的第三方庫的最佳時(shí)機(jī)。

假設(shè)我們想要通過API拉取數(shù)據(jù)來初始化組件。我們應(yīng)該直接在計(jì)數(shù)器組件的componentDidMount()方法拉取數(shù)據(jù),但是這讓組件看起來有太多邏輯了,更可取的方案是使用容器組件來做:

var Container = React.createClass({
    getInitialState: function() {
        return {
            data: null,
            fetching: false,
            error: null
        };
    },

    render: function() {
        if (this.props.fetching) {
            return 
Loading...
; } if (this.props.error) { return (
{this.state.error.message}
); } return }, componentDidMount: function() { this.setState({fetching: true}); Axios.get(this.props.url).then(function(res) { this.setState({data: res.data, fetching: false}); }).catch(function(res) { this.setState({error: res.data, fetching: false}); }); } });

Axios是一個(gè)基于priomise的跨瀏覽器和Node.js的HTTP客戶端。

 更新階段

當(dāng)組件的屬性或者狀態(tài)更新時(shí)也需要一些方法來供我們執(zhí)行代碼,這些方法也是組件更新階段的一部分且按照以下的順序被調(diào)用:

1、當(dāng)從父組件接收到新的屬性時(shí):

2、當(dāng)通過this.setState()改變狀態(tài)時(shí):

此階段React組件已經(jīng)被插入DOM了,因此這些方法將不會(huì)在首次render時(shí)被調(diào)用。

最先被調(diào)用的方法是componentWillReceiveProps(),當(dāng)組件接收到新屬性時(shí)被調(diào)用。我們可以利用此方法為React組件提供一個(gè)在render之前修改state的機(jī)會(huì)。在此方法內(nèi)調(diào)用this.setState()將不會(huì)導(dǎo)致重復(fù)render,然后可以通過this.props訪問舊的屬性。例如計(jì)數(shù)器組件,如果我們想要在任何時(shí)候父組件傳入“initialCount”時(shí)更新狀態(tài),可以這樣做:

...
componentWillReceiveProps: function(newProps) {
    this.setState({count: newProps.initialCount});
},
...

shouldComponentUpdate()方法允許我們自行決定下一個(gè)state更新時(shí)是否觸發(fā)重復(fù)render。此方法返回一個(gè)布爾值,且默認(rèn)是true。但是我們也可以返回false,這樣下面的(生命周期)方法將不會(huì)被調(diào)用:

componentWillUpdate()

render()

componentDidUpdate()

當(dāng)有性能瓶頸時(shí)也可以使用shouldComponentUpdate()方法(來優(yōu)化)。尤其是數(shù)百個(gè)組件一起時(shí)重新render的代價(jià)將會(huì)十分昂貴。為了證明這個(gè)猜想我們來看一個(gè)例子:

var TextComponent = React.createClass({
    shouldComponentUpdate: function(nextProps, nextState) {
        if (this.props.text === nextProps.text) return false;
        return true;
    },

    render: function() {
        return