1. 程式人生 > >React躬行記(4)——生命週期

React躬行記(4)——生命週期

  元件的生命週期(Life Cycle)包含三個階段:掛載(Mounting)、更新(Updating)和解除安裝(Unmounting),在每個階段都會有相應的回撥方法(也叫鉤子)可供選擇,從而能更好的控制組件的行為。

一、掛載

  在這個階段,元件會完成它的首次渲染,先執行初始化,再被掛載到真實的DOM中,其中依次呼叫的方法有constructor()、componentWillMount()、render()和componentDidMount()。除了render(),其他三個方法都只會執行一次。

1)constructor()

  在生命週期中,類的建構函式constructor()會率先被執行,用於初始化元件的狀態、接收外部傳遞進來的資料、繫結成員方法的this指向等工作。

2)componentWillMount()

  componentWillMount()方法會執行在render()之前,它是渲染之前的回撥函式。不過,由於在這個方法中執行的任務都能提前到constructor()中,因此實際專案中很少會用到它。

3)render()

  render()是在定義元件時必須宣告的方法,它是一個無副作用的純函式,可根據元件的props和state得到一個React元素、null或false等返回值,並且在render()方法中不能呼叫改變元件狀態的this.setState()方法。注意,將元素渲染到頁面DOM中的工作都由React負責,而不是render()方法。

4)componentDidMount()

  componentDidMount()方法會執行在render()之後,它是渲染之後的回撥函式。此時元件已被掛載到頁面中,可以執行DOM相關的操作,例如非同步讀取伺服器中的資料並填充到元件中、呼叫jQuery程式碼等。

  下面的元件沒有實際用途,僅僅是為了演示四個回撥函式,其中componentWillMount()和componentDidMount()都成功呼叫了this.setState()方法。

class Btn extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      name: props.name
    };
  }
  componentWillMount() {
    this.setState({age: 28});
  }
  render() {
    return <button>{this.state.name}</button>;
  }
  componentDidMount() {
    $.post("server.php", {id:1}, json => {
      this.setState({age: json.data.age});
    }, "json");
  }
}

二、更新

  引起元件更新(即重新渲染)的方式有三種,第一種是由父元件向下傳遞props(即呼叫父元件的render()方法)引起的更新,依次會呼叫五個方法:componentWillReceiveProps()、shouldComponentUpdate()、componentWillUpdate()、render()和componentDidUpdate()。第二種是通過改變自身state(即呼叫this.setState()方法)引起的更新,會忽略componentWillReceiveProps()方法,只執行四個回撥函式。第三種是通過元件的forceUpdate()方法強制更新,只有後三個回撥函式會被執行。在下面的元件中,定義了更新階段的五個回撥函式,並且點選按鈕就會觸發強制更新。

class Btn extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      name: "strick"
    };
  }
  dot() {
    this.setState({name: "freedom"});
    this.forceUpdate();            //強制更新
  }
  
  componentWillReceiveProps(nextProps) { }
  shouldComponentUpdate(nextProps, nextState) { return true; }
  componentWillUpdate(nextProps, nextState) { }
  render() {
    return <button onClick={this.dot.bind(this)}>{this.state.name}</button>;
  }
  componentDidUpdate(prevProps, prevState) { }
}

1)componentWillReceiveProps()

  componentWillReceiveProps()方法常用於執行props更新後的邏輯,只有第一種更新方式才會呼叫它,該方法能接收一個名為nextProps的引數,表示父元件傳遞進來的新的props。當需要通過this.setState()方法將nextProps中的資料同步到內部狀態時,要先比較nextProps和this.props中的值是否相同,再決定是否執行同步。由於在componentWillReceiveProps()中能呼叫this.setState()方法,因此為了避免進入一個死迴圈,在呼叫this.setState()方法更新元件時就不會觸發它。

2)shouldComponentUpdate()

  shouldComponentUpdate()用於決定是否繼續元件的更新,它能接收2個引數:nextProps和nextState,分別表示新的props和state,通過比較nextProps、nextState和元件當前的this.props、this.state能得出一個布林型別的返回結果。當返回結果為false時,元件會停止更新,後續的componentWillUpdate()、render()和componentDidUpdate()也不會被執行。將這個方法使用恰當的話,能減少冗餘的渲染,優化元件的效能。

3)componentWillUpdate()和componentDidUpdate()

  componentWillUpdate()和componentDidUpdate()分別執行在render()之前和之後,它們都能接收2個引數,前者提供更新後的props和state,後者提供更新前的props和state。在componentWillUpdate()中,不能呼叫this.setState()方法,以免發生不必要的死迴圈。

三、解除安裝

  當元件在從DOM中被解除安裝之前,會觸發一個無引數的componentWillUnmount()方法。在該方法內適合做些清理的工作,例如清除定時器、移除多餘的DOM元素等。下面演示了處理解除安裝的過程,限於篇幅省略了元件的建構函式和render()方法,只給出了關鍵程式碼。

class Btn extends React.Component {
  componentWillUnmount() {
    clearInterval(timeout);
  }
}
var container = document.getElementById("container");
ReactDOM.render(<Btn>提交</Btn>, container);
ReactDOM.unmountComponentAtNode(container);            //移除DOM中的元件

四、流程圖

  接下來用一張總的流程圖(如圖5所示)來說明生命週期各個方法之間的關係,灰底的方法表示在其內部能呼叫this.setState()方法。

圖5  元件生命週期流程圖

&n