在构造函数中定义状态或使用属性初始值设定项更好吗?

时间:2016-06-13 11:14:14

标签: reactjs ecmascript-next

根据this babel文档,使用ES6 +和React的正确方法是初始组件如下:

class Video extends React.Component {
  static defaultProps = {
    autoPlay: false,
    maxLoops: 10,
  }
  static propTypes = {
    autoPlay: React.PropTypes.bool.isRequired,
    maxLoops: React.PropTypes.number.isRequired,
    posterFrameSrc: React.PropTypes.string.isRequired,
    videoSrc: React.PropTypes.string.isRequired,
  }
  state = {
    loopsRemaining: this.props.maxLoops,
  }
}

但是一些官方的例子,比如Dan Abramov自己的React DnD模块,使用ES6 +,但仍然在构造函数中定义状态:

constructor(props) {
    super(props);
    this.moveCard = this.moveCard.bind(this);
    this.state = {
       // state stuff
    }
}

现在,作为React的重要贡献者的Dan Abramov可能知道他可以在构造函数之外定义状态,但仍然选择在构造函数中执行它。

所以我只是想知道哪种方式更好,为什么?

3 个答案:

答案 0 :(得分:67)

答案 1 :(得分:6)

它们是等效的,因为class field proposal是构造函数主体代码的语法糖。

如果不需要显式构造函数(创建临时局部变量等),则可以省略constructor以便使用类字段。

显式构造函数的问题在于,super参数(props)经常被错误地省略,这可能会导致问题:

constructor() {
    super();
    this.state = { foo: this.props.foo } // this.props is undefined
}

显式构造函数可能对可读性有利。方法通常放在constructor下面,甚至包括箭头属性。这不能按预期方式工作,因为类字段是按照列出的顺序分配的:

state = { foo: { method: this.someMethod } } // this.someMethod is undefined

someMethod = () => ...;

在这种情况下,显式构造函数可能会导致代码更具可读性:

constructor(props) {
    super(props);

    // <-- this is the place where this.someMethod is really assigned

    this.state = { foo: { method: this.someMethod } }
}

someMethod = () => ...;

答案 2 :(得分:1)

Dan的代码实际上有一个微妙的错误,这就是为什么我建议尽可能使用初始化程序。 React组件构造函数有两个参数 - props和上下文。他没有将它传递给父构造函数,而其他需要它的开发人员很容易错过它。

有时你别无选择,比如初始化程序依赖于构造函数参数,所以只需记住将所有参数传递给父级。

在尝试了几件事后,看起来React没有我想到的问题。你可以将任何你想要的东西传递给父构造函数,它会很好。 E.g:

class MyComponent extends React.Component {
  constructor(props) {
    super({})
  }

  render() {
    // this.props will still be set correctly here
  }
}

我仍然建议使用初始值设定项,因为不必调用父构造函数是一件值得思考的事情。