將 React 組件 由 createClass 重構(gòu)為 ES6 寫法(譯)

原文地址: http://www.newmediacampaigns.com/blog/refactoring-react-components-to-es6-classes

正文

我們團隊是 React框架 的忠實粉絲,并且已經(jīng)嘗試使用 ES6 來進行 React 開發(fā)。很高興看到從 React 0.13 開始,官方推薦使用 ES6 類語法來進行組件的定義。

將 React 組件從 React 0.12 通過 createClass 定義的組件重構(gòu)為基于 0.13 版本使用 ES6 類定義的組件只需要以下簡單的幾步。在后文中將一步一步的給予說明。

第一步 - 從組件構(gòu)造函數(shù)中取出 propTypesgetDefaultProps 放到組件屬性上

createClass 這個 API 期望的參數(shù)為一個字面量對象,同時可以定義方法和屬性。而 ES6 中的類定義只允許定義方法,而不允許定義屬性(The committee's rationale for this was primarily to have a minimal starting point for classes which could be easily agreed upon and expanded in ES7)。因為這個原因?qū)τ?propTypes 這樣的屬性,我們必須將其定義在 類定義 之外(we must define them outside of the class definition)。

另外的一個變化之處是在 React 0.13 版本中, props 屬性被定義為 immutable data(不可變數(shù)據(jù)),所以 getDefaultProps 作為一個函數(shù)將不能在繼續(xù)使用,因此也需要將其重構(gòu)到構(gòu)造函數(shù)之外。

Before:

var ExampleComponent = React.createClass({
    propTypes: {
      aStringProps: React.PropTypes.string
    },
    getDefaultProps: function() {
      return { aStringProps: '' }
    }
})

After:

var ExampleComponent = React.createClass({...});
ExampleComponent.propTypes = {
  aStringProps: React.PropTypes.string
};
ExampleComponent.defaultProps = {
  aStringProps: ''
}

第二步 - 從 createClass 到使用 ES6 Class 語法定義組件

ES6 Class 語法比起傳統(tǒng)的對象字面量更為簡潔。對于方法的定義不需要再使用 function 關(guān)鍵字,也不需要 , 來分開多個方法。

Before:

var ExampleComponent = React.createClass({
  render: function() {
    return <div onClick={ this._handleClick }>Hello World!</div>
  },
  _handleClick: function() {
    console.log(this);
  }
})

After:

class ExampleComponent extends React.component {
  render() {
    return <div onClick={ this._handleClick }>Hello World!</div>
  }
  _handleClick() {
    console.log(this)
  }
}

第三步 - 綁定實例方法和回調(diào)到實例上

使用 createClass 時有一個便捷之處是默認的就將提供的方法綁定到了組件實例上。比如前面例子中的 _handleClick 方法里的 this 將會指向當前這個組件實例。當使用 ES6 Class 語法的時候,我們必須要手動為這些方法綁定執(zhí)行上下文。React 團隊推薦將綁定工作放在構(gòu)造函數(shù)內(nèi)完成(This is a stopgap until ES7 allows property initializers)

Before:

class ExampleComponent extends React.Component {
  render() {
    return <div onClick={ this._handleClick }> Hello World! </div>
  }
  _handleClick() {
    console.log(this);    // this is undefined
  }
}

After:

class ExampleComponent extends React.Component {
  constructor() {
    super();
    this._handleClick = this._handleClick.bind(this);
  }
  render() {
    return <div onClick={ this._handleClick }> Hello World! </div>
  }
  _handleClick() {
    console.log(this);  // this is an ExampleComponent
  }
}

在文章結(jié)尾將會介紹我們對 Component 類的擴展,該類將會更好的實現(xiàn)自動綁定的過程。

第四步 - 將初始 state 定義移動到構(gòu)造函數(shù)中

React 團隊推薦使用一種更符合語義的方法來定義初始 state(在構(gòu)造函數(shù)中將初始值存放在對應(yīng)屬性上)。也就是可以在構(gòu)造函數(shù)中將 getInitialState 方法中的返回值賦值到 該實例對象的 this.state 屬性上。

Before:

class ExampleComponent extends React.Component {
  getInitialState() {
    return Store.getState();
  }
  constructor() {
    super();
    this._handleClick = this._handleClick.bind(this);
  }
  // ...
}

After:

class ExampleComponent extends React.Component {
  constructor() {
    super();
    this._handleClick = this._handleClick.bind(this);
    this.state = Store.getState();
  }
  // ...
}

Conclusion

使用上面提到的少許的幾步將一個存在的 React 組件轉(zhuǎn)化為 ES6 Class 語法定義的組件是很簡單的。同時直到 JavaScript 語法上有 mixins 特性之前使用 React.createClass 也是不被反對的。

Bonus Step - 更簡潔的 this 綁定方法:

Before:

class ExampleComponent extends React.Component {
  constructor() {
    super();
    this._handleClick = this._handleClick.bind(this);
    this._handleFoo = this._handleFoo.bind(this);
  }
  // ...
}

After:

class BaseComponent extends React.Component {
  _bind(...methods) {
    methods.forEach( (method) => this[method] = this[method].bind(this) );
  }
}

class ExampleComponent extends BaseComponent {
  constructor() {
    super();
    this._bind('_handleClick', '_handleFoo');
  }
  // ...
}

我們通過 _bind 方法將重復(fù)的綁定方法提取到 BaseComponent 類上使綁定的方法更為簡潔。_bind 方法使用了很多 ES6 的特性: methods 參數(shù)使用了 rest parameter, forEach 里面使用了 箭頭函數(shù)(arrow function).

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容