[译] 构造函数已死,构造函数万岁!

构造函数已死,构造函数万岁!

向 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前端后端区块链产品设计人工智能等领域,想要查看更多优质译文请持续关注 掘金翻译计划官方微博知乎专栏

相关文章
相关标签/搜索