Подтвердить что ты не робот

Лучше ли определять состояние в конструкторе или использовать инициализаторы свойств?

Согласно этой документации для 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
    }
}

Теперь Дэн Абрамов, будучи значительным вкладчиком в Реакт, вероятно, знает, что он может определить состояние вне конструктора, но все же предпочитает делать это внутри конструктора.

Так что мне просто интересно, какой путь лучше и почему?

4b9b3361

Ответ 1

Я считаю, что это вопрос личных предпочтений. Транспортированный вывод одинаков с точки зрения семантики.

Ответ 2

Они эквивалентны, потому что предложение поля класса является синтаксическим сахаром для кода тела конструктора.

В случае, если нет необходимости в явном конструкторе (создании временных локальных переменных и т.д.), 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 = () => ...;

Ответ 3

В коде Дэн есть тонкая ошибка, поэтому я рекомендую использовать инициализаторы, когда это возможно. Конструкторы реактивных компонентов принимают два аргумента - реквизиты и контекст. Он не передавал его родительскому конструктору, и его можно было легко упустить другим разработчиком, которому это было необходимо.

Иногда у вас нет выбора, например, когда инициализатор зависит от аргументов конструктора, поэтому просто не забудьте передать все аргументы родительскому.

Попробовав несколько вещей, похоже, что у Реакта нет проблемы, о которой я думал. Вы можете передать все, что хотите, родительскому конструктору, и все будет хорошо. Например:.

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

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

Я по-прежнему рекомендую использовать инициализаторы, поскольку не нужно вызывать родительский конструктор, о чем меньше думать.