天天看點

React Object實作React對象

不使用ES6

通常情況下,定義一個React元件可以使用ES6規範中的class關鍵字:

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

如果不使用ES6文法,可以直接使用 

React.createClass

 來實作相同的功能:

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

聲明Prop的檢查類型以及預設Props值

在前面的博文(

React prop類型檢查與Dom

)中介紹了如何規約Prop的參數值,給出的例子都是用ES6實作的:

class Greeting extends React.Component {
  // ...
}

Greeting.propTypes = {
  name: React.PropTypes.string
};

Greeting.defaultProps = {
  name: 'Mary'
};           

在使用 

React.createClass

 時,可以通過設定傳入的對象的一個屬性值—— 

propTypes

 來指定參數類型,通過 

getDefaultProps()

 方法來設定每個參數的預設值:

var Greeting = React.createClass({
  propTypes: {
    name: PropTypes.string
  },

  getDefaultProps: function() {
    return {
      name: 'Mary'
    };
  },

  // ...

});           

設定初始化狀态

在ES6的 class 結構中,我們可以在構造函數中設定初始化狀态:

class Counter extends React.Component {
  constructor(props) {
    super(props);
    this.state = {count: props.initialCount};
  }
  // ...
}           

React.createClass

 時,可以為傳入的對象參數添加一個  

getInitialState

 方法并傳回一個初始狀态值:

var Counter = React.createClass({
  getInitialState: function() {
    return {count: this.props.initialCount};
  },
  // ...
});           

自動綁定

當使用ES6的 class 關鍵字聲明一個React元件時,類中的方法遵循與正常的方法一樣的定義。這就意味着在類中申明的方法在執行時并不會自動屬于目前執行個體,必須在構造函數中顯示的使用.bind(this)方法綁定到目前執行個體:

class SayHello extends React.Component {
  constructor(props) {
    super(props);
    this.state = {message: 'Hello!'};
    // 必須,否在在handleClick中this将指向調用對象
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick() {
    alert(this.state.message);
  }

  render() {
    return (
      <button onClick={this.handleClick}>
        Say hello
      </button>
    );
  }
}           

React.createClass

 時不必綁定所有的方法:

var SayHello = React.createClass({
  getInitialState: function() {
    return {message: 'Hello!'};
  },

  handleClick: function() {
    alert(this.state.message);
  },

  render: function() {
    return (
      <button onClick={this.handleClick}>
        Say hello
      </button>
    );
  }
});           

以上的特性意味着使用ES6編寫代碼每一個方法都會額外增加一些樣闆式代碼,但是對于大型應用來說代碼結構更清晰。

如果十分排斥樣闆式代碼,可以啟用Babal的 類屬性功能( 

Class Properties

 ),利用雙箭頭來建立方法:

class SayHello extends React.Component {
  constructor(props) {
    super(props);
    this.state = {message: 'Hello!'};
  }

  handleClick = () => {
    alert(this.state.message);
  }

  render() {
    return (
      <button onClick={this.handleClick}>
        Say hello
      </button>
    );
  }
}           

需要注意的是,目前這個功能還是實驗性的,雙箭頭的表達式很有可能會調整。該提議不一定會被委員會接納。

如果非常想要嘗試這種寫法,你可以有這幾種實作方式:

  1. 在構造函數中綁定方法。
  2. 使用箭頭來定義方法。
  3. 使用 

    React.createClass

     。

代碼混合器

注意:

ES6在目前的方案中并不支援代碼混合功能,是以在使用ES6編寫React代碼時并不能實作相關功能。

官方也收到許多在使用混合器時遇到的問題,強烈建議不要在新的代碼中使用混合器功能。

以下的内容僅供參考。

某些時候2個不同的元件需要共享一些相同的方法或者功能。這種情況我們稱為 橫切關聯( 

cross-cutting concerns

)。 

React.createClass

 可以通過繼承來實作元件間公用相同方法。

一個通用的案例是一個元件需要定期更新自己的狀态,隻要使用

setInterval()

就可以實作。但是當您不再需要它來節省記憶體時,取消定時器是很重要的。React提供了生命周期方法來通知建立和銷毀事件。下面的代碼建立了一個肩帶的混合器,混合器的作用是當元件被銷毀之前,可以清除已有的定時器:

// 定義一個混合器
var SetIntervalMixin = {
  //元件将要被渲染時調用
  componentWillMount: function() {
    this.intervals = [];
  },
  // 設定定時器方法
  setInterval: function() {
    this.intervals.push(setInterval.apply(null, arguments));
  },

  //元件将要被解除安裝時調用
  componentWillUnmount: function() {
    this.intervals.forEach(clearInterval);
  }
};

var TickTock = React.createClass({
  mixins: [SetIntervalMixin], // 設定混合器
  getInitialState: function() {
    return {seconds: 0};
  },
  componentDidMount: function() {
    this.setInterval(this.tick, 1000); // 調用混合器中的setInterval 方法
  },
  tick: function() {
    this.setState({seconds: this.state.seconds + 1});
  },
  render: function() {
    return (
      <p>
        React has been running for {this.state.seconds} seconds.
      </p>
    );
  }
});

ReactDOM.render(
  <TickTock />,
  document.getElementById('example')
);           

如果元件使用了多個混合器并且很多混合器定義了相同的生命周期方法,比如同時定義了componentWillUnmount方法當元件解除安裝時登出某些資源。所有混合器的生命周期方法都會被調用,React會按照混合器設定的順序來執行。

不使用JSX

對于React來說JSX并不是必須要使用的表達式。當在環境中不想在家額外的編譯工具時尤其适用。

每一個JSX的元素都僅僅是

React.createElement(component, props, ...children)

的文法糖,是以任何使用JSX表達式實作的内容都可以直接用JavaScript來實作。

例如下面使用JSX編碼的例子:

class Hello extends React.Component {
  render() {
    return <div>Hello {this.props.toWhat}</div>;
  }
}

ReactDOM.render(
  <Hello toWhat="World" />,
  document.getElementById('root')
);           

如果我們不想使用JSX,可以将其修改為:

class Hello extends React.Component {
  render() {
    return React.createElement('div', null, `Hello ${this.props.toWhat}`);
  }
}

ReactDOM.render(
  React.createElement(Hello, {toWhat: 'World'}, null),
  document.getElementById('root')
);           

如果你對JSX如何轉換成JavaScript有很強的興趣,可以打開這個線上編譯器試試:

the online Babel compiler

元件被編譯成一段字元串、由 

React.Component

建立的子類或者一個普通無狀态的元件。

如果對編碼時每次都要鍵入長長React.createElement感到痛苦,一個常見的模式是配置設定一個别名:

const e = React.createElement;

ReactDOM.render(
  e('div', null, 'Hello World'),
  document.getElementById('root')
);           

繼續閱讀