[譯] 構造函數已死,構造函數萬歲!

構造函數已死,構造函數萬歲!

向 React 組件里老掉牙的類構造函數(class constructor)說再見

Photo by Samuel Zeller on Unsplash前端

儘管無狀態函數組件(SFCs)是一件趁手的神兵利器,但 ES6 類組件仍舊是建立 React 組件及其狀態和生命週期鉤子函數的默認方式。react

假設一個 ES6 類組件以下例所示(只展現簡化過的部分代碼)。android

class Foo extends Component {
  constructor(props) {
    super(props); 
    this.state = { loading: true };
  }
複製代碼
async componentDidMount() {
    const data = await loadStuff();
    this.setState({ loading: false, data });
  }
複製代碼
render() {
    const { loading, data } = this.state;
    return (
      {loading ? <Loading /> : <View {...data} />}
    );
  }
}
複製代碼

constructor 中初始化 state,並於 componentDidMount 中異步加載數據,而後根據 loading 的狀態來渲染 View 這個組件。對我而言這是至關標準的模式,若是你熟悉我以前的代碼風格的話。ios

類屬性

咱們都知道 constructor 正是咱們初始化實例屬性的地方,就像本例中這個 state 同樣。若是你正成竹在胸地對本身說,『正是如此!』,那麼你可說對了……但對於即將問世的 ES.next 類屬性提案class properties proposal 而言卻並不是如此,目前這份提案正處於第三階段。git

按照新的提案來講,咱們能夠用以下方式直接定義類屬性。es6

class Foo extends Component {
  state = { loading: true };
  ...
}
複製代碼

Babel 將會在後臺轉譯你的代碼並添加上一個 constructor。下圖是 Babel 將你的代碼片斷轉譯過來的結果。github

請注意這裏 Babel 其實是傳遞了全部參數到 super - 不只僅是 props。它也會將 super 的返回值傳遞迴調用者。二者雖然感受有些小題大作,但確實須要這樣。express

此處仍存在構造函數,你只是看不見而已。後端

綁定方法

使用 constructor 的另外一重緣由是將函數綁定到 this,以下所示。數組

class Foo extends Component {
  constructor(props) {
    super(props); 
    this.myHandler = this.myHandler.bind(this);
  }
複製代碼
myHandler() {
    // some code here that references this
  }
  ...
}
複製代碼

但有些人用直接將函數表達式指定給一個類屬性的方法徹底避免了這個問題,不過這又是另外一碼事了。想了解更多能夠參考我寫的其餘基於 ES6 類的 React 文章。 Demystifying Memory Usage using ES6 React Classes.

Demystifying Memory Usage using ES6 React Classes

那讓咱們假設一下你隸屬 bind 陣營(即使不是也煩請耐心看完)。咱們仍是得須要在 constructor 進行綁定對吧?那倒不必定了。咱們能夠在這裏使用和上述處理類屬性同樣的方法。

class Foo extends Component {
  myHandler = this.myHandler.bind(this);
  myHandler() {
    // some code here that references this
  }
  ...
}
複製代碼

用 props 來初始化狀態

那若是你須要從 props 中派生出初始 state,比方說初始化一個默認值?那這樣總該須要使用到 constructor 了吧?

class Foo extends Component {
  constructor(props) {
    super(props); 
    this.state = {
      color: this.props.initialColor
    };
  }
  render() {
    const { color } = this.state;
    return (
      <div>
       {color}
      </div>
    );
  }
}
複製代碼

並非哦!類屬性再次救人於水火!咱們能夠同時取到 thisprops

class Foo extends Component {
  state = {
    color: this.props.initialColor
  };
  ...
}
複製代碼

獲取數據

那也許咱們須要 constructor 獲取數據?基本上不須要。就像咱們在第一個代碼示例看到的那樣,任何數據的加載都應在 componentDidMount 裏完成。但爲什麼獨獨在 componentDidMount呢?由於這樣能夠確保在服務器端運行組件時不會執行獲取數據 - 服務器端渲染(SSR)同理 — 由於 componentDidMount 不會在服務器端執行。

結論

綜上能夠看出,咱們再也不須要一個 constructor(或者其餘任何實例屬性)來設置初始 state。咱們也不須要構造函數來把函數綁定到 this,以及從 props 設置初始的 state。同時咱們也徹底不須要在 constructor 裏面獲取數據。

那爲何咱們還須要在 React 組件中使用構造函數呢?

怎麼說呢……你還真的不須要

不過,要是你在某些模棱兩可的使用實例裏,遇到須要同時從客戶端和服務器端在一個組件裏初始化什麼東西的狀況,構造函數仍然是個好的出路。你還有 componentWillMount 這個鉤子函數能夠用。 從內部機制來看,React 在客戶端和服務器端都新建好了這個類(即調用構造函數)之後,就會當即調用這個鉤子函數。

因此對 React 組件來講,我堅信這一點:構造函數已死,構造函數萬歲!


I also write for the American Express Engineering Blog. Check out my other works and the works of my talented co-workers at AmericanExpress.io. You can also follow me on Twitter.


掘金翻譯計劃 是一個翻譯優質互聯網技術文章的社區,文章來源爲 掘金 上的英文分享文章。內容覆蓋 AndroidiOS前端後端區塊鏈產品設計人工智能等領域,想要查看更多優質譯文請持續關注 掘金翻譯計劃官方微博知乎專欄

相關文章
相關標籤/搜索