組件

React提供React.Component,我們可以透過使用組件,拆分UI為可以重複使用的獨立部分。React.Component是一個抽象的base class。我們甚少直接運用React.Component,通常是透過創建一個子類,並使用render()方法。

例子:

class Greeting extends React.Component {
  render() {
    return <h1>Hello, {this.props.name}</h1>;
  }
}

如果你不選擇使用ES6,你可以使用模組create-react-class。你可以參考React Without ES6。 下面這一段和ES6的寫法效果一樣:

var createReactClass = require('create-react-class');
var Greeting = createReactClass({
  render: function() {
    return <h1>Hello, {this.props.name}</h1>;
  }
});

組件生命週期

每一個組件都會有幾個生命週期的方法,你可以在程序運行的指定時間,透過覆蓋他們來運行特定代碼。對於這些方法,我們會用will-來表示它會在某些事情發生之前的一刻被調用,而did-則是表示它會在某些事情發生之後的一刻被調用。本文會細說加載組件中發生了什麼事情。

加載 (Mounting)

  1. constructor()
  2. componentWillMount()
  3. render()
  4. componentDidMount()

更新 (Updating)

當 props 或者 state 更新的時候,下面這些方法會被調用:

  1. componentWillReceiveProps()
  2. shouldComponentUpdate()
  3. componentWillUpdate()
  4. render()
  5. componentDidUpdate()

斷開連接 (Unmounting)

當組件脫離DOM的時候,下面這個方法回被調用:

  1. componentWillUnmount()

其他內置方法

  1. setState()
  2. forceUpdate()

我們會在下文討論一下React是如何加載組件。

{% img /img/react-mount.svg 300 auto React LifeCycle Mount %}

constructor()

constructor(props)

在React加載組件之前,它會調用constructor。你可以在constructor中去賦予組件的初始state。如果你使用props創造初始state的話,這也是可以接受的。這會很有效地fork組件的props,然後賦予初始state的值。

有效的constructor例子:

constructor(props) {
  super(props);
  this.state = {
    color: props.initialColor
  };
}
注意事項
  1. 如果你不需要賦予初始state,你不需要在 React 的組件中植入constructor
  2. 當你使用在React.Component的子類中加載constructor()方法時,你應該第一時間調用super(props),而不是在任何statement之後。不然,我們獲取this.props值的時候,它會是undefined
  3. 在一些類似上面的例子,state未必會及時與任何的props更新。如果你需要同步state的話,你其實是想要lift the state up

componentWillMount()

componentWillMount()

它會在組件render()之前執行一次,然後不能再執行。如果在這裡定義了setState方法,頁面只會在加載之前更新一次,不會重複渲染。React 官方推薦使用constructor()代替這個方法。

render()

React.Component必須有這個方法,即使你返回null,或者false。當你返回null,或者false的時候,ReactDOM.findDOMNode(this) 會返回null

當它被調用的時候,它會檢查this.propsthis.state,然後返回一個單獨的 React 元素。這個元素會是一個純正的DOM組件,例如<div />,或者自定義的 composite 組件。

注意事項
  1. render()方法應該是pure:它不會改寫任何組件的state。每一次調用它都會返回同樣的結果。它不會直接接觸到瀏覽器層面。
  2. 如果你需要接觸到瀏覽器層面,你應該在componentDidMount()或者其他生命週期方法中接觸瀏覽器。
  3. 保持render()方法 pure 來讓組件更加容易被人理解。

componentDidMount()

componentDidMount()

它會在組件加載之後執行一次。如果你的初始程序需要DOM nodes,你應該在這裡寫。如果你需要從其他地方加載資料,這裡也是一個不錯的地方去執行網絡請求。如果在這裡定義了setState方法,會觸發重複渲染。

測試代碼

class Greeting extends React.Component {
  _log(method, args) {
    console.log(method, args);
  }

  constructor(props) {
    super(props);
    console.log('constructor', props);
  }

  render() {
    this._log('render', this.props.name);
    return <h1>Hello, {this.props.name}</h1>;
  }

  componentWillMount() {
    this._log('componentWillMount');
  }

  componentDidMount() {
    this._log('componentDidMount');
  }
}

ReactDOM.render(
  <Greeting name="Calpa" />,
  document.getElementById('app')
);

Console Output:

"constructor" Object {
  name: "Calpa"
}
"componentWillMount" undefined
"render" "Calpa"
"componentDidMount" undefined

你可以在CodePen中獲取,並測試這段代碼。

不知道拿哪一張當封面好。。。

如果你覺得我的文章對你有幫助的話,希望可以推薦和交流一下。歡迎關注和 Star 本博客或者關注我的 Github