React.js學習筆記之組件生命週期

React.js學習筆記之組件生命週期

@(React學習)javascript

什麼是組件

React 容許將代碼封裝成組件(component),而後像插入普通 HTML 標籤同樣,在網頁中插入這個組件。html

組件類只能包含一個頂層標籤,不然會報錯。java

var HelloXiaowang = React.createClass({
  render: function() {
    return <h1>Hello {this.props.name}</h1>;
  }
});

ReactDOM.render(
  <HelloXiaowang name="junyan" />,
  document.getElementById('shuaige')
);

上面代碼中,變量 HelloXiaowang 就是一個組件類。模板插入 HelloXiaowang /> 時,會自動生成 HelloXiaowang 的一個實例(下文的"組件"都指組件類的實例)。react

render

全部組件類都必須有本身的render方法,用於輸出組件
ReactElement render ( )git

當調用的時候,會檢測 this.props 和 this.state,返回一個單子級組件。該子級組件能夠是虛擬的本地 DOM 組件(好比 div /> 或者 React.DOM.div()),也能夠是自定義的複合組件。github

var HelloXiaowang = React.createClass({
  render: function() {
    return <h1>Hello {this.props.name}</h1>;
  }
});

render ( ) 函數應該是純粹的,也就是說該函數不修改組件 s瀏覽器

tate,每次調用都返回相同的結果,不讀寫 DOM 信息,也不和瀏覽器交互(例如經過使用 setTimeout)。若是須要和瀏覽器交互,在 componentDidMount() 中或者其它生命週期方法中作這件事。保持 render() 純粹,可使服務器端渲染更加切實可行,也使組件更容易被理解。服務器

生命週期

組件本質上是狀態機,輸入肯定,輸出必定肯定app

狀態機本質上是狀態與轉移的結合。當狀態發生轉換時會觸發不一樣的鉤子函數,從而讓開發者有機會作出相應。
組件的聲明週期分紅三個狀態:函數

  • Mounting:初始化階段(已插入真實 DOM)

  • Updating:運行中階段(正在被從新渲染)

  • Unmounting:銷燬階段(已移出真實 DOM)

初始化階段Mounting

類建立完成以後,就能夠進行實例化。

初始化階段可使用的函數:

  • getDefaultProps: 只調用一次,實例之間共享引用

  • getInitialState: 初始化每一個實例特有的狀態

  • componentWillMount: render以前最後一次修改狀態的機會。若是在這個方法內調用setState,render()將會感知到更新後的state,將會執行僅一次,儘管state改變了。

  • render: 只能訪問this.props和this.state,只有一個頂層組件,不容許修改狀態和DOM輸出

  • componentDidMount: 成功render並渲染完成真實DOM以後觸發,能夠修改DOM

調用順序

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

  1. getDefaultProps

  2. getInitialState

  3. componentWillMount

  4. render

  5. componentDidMount

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

  1. getDefaultProps

  2. getInitialState

  3. componentWillMount

  4. render

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

實例

getDefaultProps方法不是在組件建立的時候調用,而是在createClass時調用。

var count = 0;
var HelloWorld = React.createClass({
    getDefaultProps:function(){
        return {name:"dada"};
    },
    getInitialState:function(){
        return {
            myCount:count++,
            ready:false
        };
    },
    componentWillMount:function(){
        this.setState({ready:true});
    },
    render:function(){
        return <p>Hello,{this.props.name?this.props.name:"World"}
        <br/>{''+this.props.ready}{this.state.myCount}</p>;
    },
    componentDidMount:function(){
        $(ReactDOM.findDOMNode(this)).append("bianke");
    }
});
ReactDOM.render(<HelloWorld/>,document.getElementById('shuage'))

阮老師例子:

var Hello = React.createClass({
  getInitialState: function () {
    return {
      opacity: 1.0
    };
  },

  componentDidMount: function () {
    this.timer = setInterval(function () {
      var opacity = this.state.opacity;
      opacity -= .05;
      if (opacity < 0.1) {
        opacity = 1.0;
      }
      this.setState({
        opacity: opacity
      });
    }.bind(this), 100);
  },

  render: function () {
    return (
      <div style={{opacity: this.state.opacity}}>
        Hello {this.props.name}
      </div>
    );
  }
});

ReactDOM.render(
  <Hello name="world"/>,
  document.body
);

上面代碼在hello組件加載之後,經過 componentDidMount 方法設置一個定時器,每隔100毫秒,就從新設置組件的透明度,從而引起從新渲染。

另外組件的style屬性的設置方式要寫成style={{opacity: this.state.opacity}}

React.findDOMNode()

若是這個組件已經被初始化到DOM中,這個方法返回相應的原生瀏覽器的DOM元素。這個方法用於讀取這個DOM的值,例如表單的值與DOM的方法。在多數狀況下附加一個ref屬性與DOM節點上,用來避免使用findDOMNode。當render返回null或false時,findDOMNode也返回null。

注意:

  • findDOMNode是一個用來訪問底層DOM節點的出口。在大多數狀況下,是不鼓勵用出口,由於他穿過了組件的層

  • findDOMNode僅僅是在初始化階段的組件起做用(由於組件已經存在於DOM結構中)。若是你嘗試在還沒有在初始化階段的組件中調用這個方法(就像render()函數中組件還沒有建立就調用這個方法)會拋出異常。

  • findDOMNode不能用於沒有狀態的組件中。

  • getDOMNode已過期,不建議使用。

運行中階段Updating

此時組件已經渲染好而且用戶能夠與它進行交互,好比鼠標點擊,手指點按,或者其它的一些事件,致使應用狀態的改變

運行中階段可使用的函數

  • componentWillReceiveProps:父組件修改屬性觸發,能夠修改新屬性、修改狀態。它是在組件發生改變以前觸發

  • shouldComponentUpdate:返回false會阻止render調用

  • componentWillUpdate:不能修改屬性與狀態

  • render: 只能訪問this.props和this.state,只有一個頂層組件,不容許修改狀態和DOM輸出

  • componentDidUpdate:能夠修改DOM

componentWillReceiveProps

在組件接收到新的 props 的時候調用。在初始化渲染的時候,該方法不會調用。
用此函數能夠做爲 react 在 prop 傳入以後, render()渲染以前更新 state 的機會。老的 props 能夠經過this.props獲取到。在該函數調用用this.setState()將不會引發第二次渲染。

componentWillReceiveProps: function(nextProps) {
  this.setState({
    likesIncreasing: nextProps.likeCount > this.props.likeCount
  });
}

對於 state,沒有類似的方法:componentWillReceiveState。將要傳進來的 prop 可能會引發 state 改變,反之則否則。若是須要在 state 改變的時候執行一些操做,請使 componentWillUpdate

shouldComponentUpdate

在接收到新的 props 或者 state,將要渲染以前調用。該方法在初始化渲染的時候不會調用,在使用 forceUpdate 方法的時候也不會。
若是肯定新的 props 和 state 不會致使組件更新,則此處應該 返回 false。

shouldComponentUpdate: function(nextProps, nextState) {
  return nextProps.id !== this.props.id;
}

若是shouldComponentUpdate返回 false,則render()將不會執行,直到下一次 state 改變。

若是性能是個瓶頸,尤爲是有幾十個甚至上百個組件的時候,使用shouldComponentUpdate能夠提高應用的性能。

默認狀況下shouldComponentUpdate總會返回 true,在 state 改變的時候避免細微的 bug,可是若是老是當心地把 state 當作不可變的,在render()中只從 props 和 state 讀取值,此時你能夠覆蓋shouldComponentUpdate方法,實現新老 props 和 state 的比對邏輯。

componentWillUpdate

在接收到新的 props 或者 state 以前馬上調用。在初始化渲染的時候該方法不會被調用。使用該方法作一些更新以前的準備工做。

你不能在此方法中使用this.setState()。若是須要更新 state 來響應某個 prop 的改變,請使用componentWillReceiveProps

componentDidUpdate

在組件的更新已經同步到 DOM 中以後馬上被調用。該方法不會在初始化渲染的時候調用。使用該方法能夠在組件更新以後操做 DOM 元素。

調用順序

每次修改 state,都會從新渲染組件,實例化後經過 state 更新組件,會依次調用下列方法:

  1. shouldComponentUpdate

  2. componentWillUpdate

  3. render

  4. componentDidUpdate

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

實例

正確用法

var HelloXianrou = React.createClass({
    componentWillReceiveProps:function(newProps){
        console.log(newProps);
    },
    render:function () {
        console.log(4);
        return <p>Hello {this.props.name||"World"}</p>
    },
    componentDidUpdate:function () {
        $(ReactD.findDOMNode(this)).append("<p>大大是大帥哥</p>")
    }
});
var HelloDada = React.createClass({
    getInitialState:function () {
        return {name:''};
    },
    handleChange:function (e) {
        this.setState({name:e.target.value});
    },
    render:function () {
        return <div>
        <HelloXianrou name={this.state.name}></HelloXianrou>
        <br/>
        <input type="text" onChange={this.handleChange} />
        </div>
    }
});
ReactDOM.render(<HelloDada></HelloDada>,document.getElementById('reactDemo'))

銷燬階段Unmounting

銷燬階段可使用的函數

componentWillUnmount:在刪除組件以前進行清理操做,好比計時器和事件監聽器。或者清除在 componentDidMount 中建立的 DOM 元素。

ReactDOM.unmountComponentAtNode

移除一個已經初始化DOM過的React組件,清理它的操做和狀態。若是這個組件中沒有初始化過的組件,這個方法沒有任何做用。若是這個組件被銷燬則返回true,反之返回false

實例

var HelloXianrou = React.createClass({
    render:function () {
        console.log(4);
        return <p>Hello {this.props.name||"World"}</p>
    },
    componentWillUnmount:function () {
        console.log("Booooooooooom!!")
    }
});
var HelloDada = React.createClass({
    getInitialState:function () {
        return {name:''};
    },
    handleChange:function (e) {
    /* if (e.target.value == "123") {
    React.unmountComponentAtNode(document.getElementById('reactDemo')[0]);
    return;
} */
        this.setState({name:e.target.value});
    },
    render:function () {
        /* if(this.state.name == "123"){
            return <p>123</p>
        } */
        return <div>
        <HelloXianrou name={this.state.name}></HelloXianrou>
        <br/>
        <input type="text" onChange={this.handleChange} />
        </div>
    }
});
ReactDOM.render(<HelloDada></HelloDada>,document.getElementById('reactDemo'))

小結

本文主要介紹了組件的生命週期。許多方法在組件生命週期中某個肯定的時間點執行。

特別感謝

相關文章
相關標籤/搜索