React:組件的生命週期

在組件的整個生命週期中,隨着該組件的props或者state發生改變,其DOM表現也會有相應的變化。一個組件就是一個狀態機,對於特定地輸入,它總返回一致的輸出。html

一個React組件的生命週期分爲三個部分:實例化、存在期和銷燬時。react

實例化

當組件在客戶端被實例化,第一次被建立時,如下方法依次被調用:git

一、getDefaultProps
二、getInitialState
三、componentWillMount
四、render
五、componentDidMountcanvas

當組件在服務端被實例化,首次被建立時,如下方法依次被調用:數據結構

一、getDefaultProps
二、getInitialState
三、componentWillMount
四、renderui

componentDidMount 不會在服務端被渲染的過程當中調用。this

getDefaultProps

對於每一個組件實例來說,這個方法只會調用一次,該組件類的全部後續應用,getDefaultPops 將不會再被調用,其返回的對象能夠用於設置默認的 props(properties的縮寫) 值。spa

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);

也能夠在掛載組件的時候設置 props:日誌

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

或者調用 setProps (通常不須要調用)來設置其 props:code

var data = [{title: 'Hello'}];
var Hello = React.render(<Demo />, document.body);
Hello.setProps({data:data});

但只能在子組件或組件樹上調用 setProps。別調用 this.setProps 或者 直接修改 this.props。將其當作只讀數據。

React經過 propTypes 提供了一種驗證 props 的方式,propTypes 是一個配置對象,用於定義屬性類型:

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
        ...
    },
    
    //...
})

組件初始化時,若是傳遞的屬性和 propTypes 不匹配,則會打印一個 console.warn 日誌。若是是可選配置,能夠去掉.isRequired。經常使用的 PropTypes 以下:

PropTypes

getInitialState

對於組件的每一個實例來講,這個方法的調用有且只有一次,用來初始化每一個實例的 state,在這個方法裏,能夠訪問組件的 props。每個React組件都有本身的 state,其與 props 的區別在於 state只存在組件的內部,props 在全部實例中共享。

getInitialState 和 getDefaultPops 的調用是有區別的,getDefaultPops 是對於組件類來講只調用一次,後續該類的應用都不會被調用,而 getInitialState 是對於每一個組件實例來說都會調用,而且只調一次。

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,都會從新渲染組件,實例化後經過 state 更新組件,會依次調用下列方法:

一、shouldComponentUpdate
二、componentWillUpdate
三、render
四、componentDidUpdate

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

componentWillMount

該方法在首次渲染以前調用,也是再 render 方法調用以前修改 state 的最後一次機會。

render

該方法會建立一個虛擬DOM,用來表示組件的輸出。對於一個組件來說,render方法是惟一一個必需的方法。render方法須要知足下面幾點:

  1. 只能經過 this.props 和 this.state 訪問數據(不能修改)

  2. 能夠返回 null,false 或者任何React組件

  3. 只能出現一個頂級組件,不能返回一組元素

  4. 不能改變組件的狀態

  5. 不能修改DOM的輸出

render方法返回的結果並非真正的DOM元素,而是一個虛擬的表現,相似於一個DOM tree的結構的對象。react之因此效率高,就是這個緣由。

componentDidMount

該方法不會在服務端被渲染的過程當中調用。該方法被調用時,已經渲染出真實的 DOM,能夠再該方法中經過 this.getDOMNode() 訪問到真實的 DOM(推薦使用 ReactDOM.findDOMNode())。

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

因爲組件並非真實的 DOM 節點,而是存在於內存之中的一種數據結構,叫作虛擬 DOM (virtual DOM)。只有當它插入文檔之後,纔會變成真實的 DOM 。有時須要從組件獲取真實 DOM 的節點,這時就要用到 ref 屬性:

var Area = React.createClass({
    render: function(){
        this.getDOMNode(); //render調用時,組件未掛載,這裏將報錯
        
        return <canvas ref='mainCanvas'>
    },
    componentDidMount: function(){
        var canvas = this.refs.mainCanvas.getDOMNode();
        //這是有效的,能夠訪問到 Canvas 節點
    }
})

須要注意的是,因爲 this.refs.[refName] 屬性獲取的是真實 DOM ,因此必須等到虛擬 DOM 插入文檔之後,才能使用這個屬性,不然會報錯。

存在期

此時組件已經渲染好而且用戶能夠與它進行交互,好比鼠標點擊,手指點按,或者其它的一些事件,致使應用狀態的改變,你將會看到下面的方法依次被調用

一、componentWillReceiveProps
二、shouldComponentUpdate
三、componentWillUpdate
四、render
五、componentDidUpdate

componentWillReceiveProps

組件的 props 屬性能夠經過父組件來更改,這時,componentWillReceiveProps 未來被調用。能夠在這個方法裏更新 state,以觸發 render 方法從新渲染組件。

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

shouldComponentUpdate

若是你肯定組件的 props 或者 state 的改變不須要從新渲染,能夠經過在這個方法裏經過返回 false 來阻止組件的從新渲染,返回 `false 則不會執行 render 以及後面的 componentWillUpdate,componentDidUpdate 方法。

該方法是非必須的,而且大多數狀況下沒有在開發中使用。

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

componentWillUpdate

這個方法和 componentWillMount 相似,在組件接收到了新的 props 或者 state 即將進行從新渲染前,componentWillUpdate(object nextProps, object nextState) 會被調用,注意不要在此方面裏再去更新 props 或者 state。

componentDidUpdate

這個方法和 componentDidMount 相似,在組件從新被渲染以後,componentDidUpdate(object prevProps, object prevState) 會被調用。能夠在這裏訪問並修改 DOM。

銷燬時

componentWillUnmount

每當React使用完一個組件,這個組件必須從 DOM 中卸載後被銷燬,此時 componentWillUnmout 會被執行,完成全部的清理和銷燬工做,在 componentDidMount 中添加的任務都須要再該方法中撤銷,如建立的定時器或事件監聽器。

當再次裝載組件時,如下方法會被依次調用:

一、getInitialState
二、componentWillMount
三、render
四、componentDidMount

反模式

在 getInitialState 方法中,嘗試經過 this.props 來建立 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>
}

通過計算後的值不該該賦給 state,正確的模式應該是在渲染時計算這些值。這樣保證了計算後的值永遠不會與派生出它的 props 值不一樣步。

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

若是隻是簡單的初始化 state,那麼應用反模式是沒有問題的。

總結

如下面的一張圖總結組件的生命週期:

clipboard.png

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

相關文章
相關標籤/搜索