Справедливости ради, зачем в React писать super(props)?

React.js

Эта статья изБлог Дэна.

Горячая точка сейчасhooks, поэтому Дэн решил написать статью оclassКомпоненты статьи 😂.

Проблемы, описанные в статье, не должны влиять на ваш кодинг, однако, если вы хотите глубже разобраться в том, как работает React, эта статья может оказаться полезной.

Первый вопрос:


Я даже не знаю, сколько раз я это писалsuper(props):

class Checkbox extends React.Component {
  constructor(props) {
    super(props);
    this.state = { isOn: true };
  }
  // ...
}

Конечно,предложение атрибута классаУпрощенный код:

class Checkbox extends React.Component {
  state = { isOn: true };
  // ...
}

В начале 2015 года версия React 0.13 ужестроить планыЭтот синтаксис поддерживается. Перед этим нам нужно продолжать писатьconstructor, а затем позвонитеsuper(props).

Теперь давайте рассмотрим предыдущее письмо:

class Checkbox extends React.Component {
  constructor(props) {
    super(props);
    this.state = { isOn: true };
  }
  // ...
}

почему мы звонимsuper? Можешь не звонить? Если он не передается при вызовеpropsШерстяная ткань? Можно ли передать другие параметры?Прокрутите вниз с этими вопросами.


В JavaScript,superСсылка на конструктор родительского класса. (В React ссылка, естественно,React.Component)

Следует отметить, что его нельзя использовать до тех пор, пока не будет вызван конструктор родительского класса.this. На самом деле это не ограничение React, а ограничение JavaScript:

class Checkbox extends React.Component {
  constructor(props) {
    // 🔴 还不能用 `this`
    super(props);
    // ✅ 现在就能用啦
    this.state = { isOn: true };
  }
  // ...
}

Пара JavaScriptthisЕсть причина для ограничений на использование. Предположим, что имеется следующее наследование:

class Person {
  constructor(name) {
    this.name = name;
  }
}

class PolitePerson extends Person {
  constructor(name) {
    this.greetColleagues(); // 🔴 不能这么干,下面会讲原因
    super(name);
  }
  greetColleagues() {
    alert('Good morning folks!');
  }
}

Если JavaScript позволяет вызыватьsuperиспользовался раньшеthis, через месяц нам нужно изменитьgreetColleaguesметод, атрибут name используется в методе:

greetColleagues() {
  alert('Good morning folks!');
  alert('My name is ' + this.name + ', nice to meet you!');
}

Но мы, возможно, забылиthis.greetColleagues();звонитsuperвызывали раньше, поэтомуthis.nameЗадания пока нет. В таком коде трудно найти ошибки.

Чтобы избежать подобных ошибок,JavaScript заставляет разработчиков сначала вызывать конструкторsuper, использоватьthis.Это ограничение также распространяется на компоненты React:

constructor(props) {
  super(props);
  // ✅ 现在可以用 `this` 啦
  this.state = { isOn: true };
}

Снова возникает вопрос: зачем проходить вpropsШерстяная ткань?


Вы можете подумать, что вам нужно датьsuperвходящийprops,иначеReact.Componentне могу инициализироватьthis.props:

// Inside React
class Component {
  constructor(props) {
    this.props = props;
    // ...
  }
}

ru...недалеко от истины - на самом деле React делаетсделал так.

Однако, если вы случайно пропуститеprops, звоните напрямуюsuper(), вы все еще можетеrenderи другие способы доступаthis.props(Можете попробовать, если не верите мне).

Почему это работает? потому чтоПосле вызова конструктора ReactpropsНазначить только что созданному объекту экземпляра:

// Inside React
const instance = new YourComponent(props);
instance.props = props;

propsЕсть причина, почему это не работает.

Когда React добавляет поддержку классов, ему необходимо поддерживать не только классы ES6, но и другие реализации классов, такие как CoffeeScript, ES6, Fable, Scala.js, а также использование классов в TypeScript.непоследовательный. Итак, даже с классами ES6 вызовsuper()React не накладывает слишком много ограничений по этому вопросу.

Но это означает, что когда вы используете React, вы можете использоватьsuper()заменятьsuper(props)Это?

Не делайте этого, потому что это принесет другие проблемы.Хотя React запустит конструктор дляthis.propsзадание, но вsuper()После вызова и до окончания конструктораthis.propsВсе равно бесполезно.

// Inside React
class Component {
  constructor(props) {
    this.props = props;
    // ...
  }
}

// Inside your code
class Button extends React.Component {
  constructor(props) {
    super(); // 😬 忘了传入 props
    console.log(props); // ✅ {}
    console.log(this.props); // 😬 undefined
  }
  // ...
}

Если метод доступа вызывается в конструктореpropsметод, то ошибку будет труднее обнаружить.Поэтому я настоятельно рекомендую всегда использоватьsuper(props), даже если это не требуется:

class Button extends React.Component {
  constructor(props) {
    super(props); // ✅ We passed props
    console.log(props); // ✅ {}
    console.log(this.props); // ✅ {}
  }
  // ...
}

Приведенный выше код гарантируетthis.propsВсегда иметь ценность.


Есть еще одна проблема, которая, возможно, долгое время преследовала разработчиков React. Вы должны были заметить, что когда вы используете Context API в классе (будь то предыдущийcontextTypesвсе еще присутствуетcontextTypeAPI),contextОба используются в качестве второго параметра конструктора.

почему бы нам не написатьsuper(props, context)? Конечно, мы могли бы сделать и так, но контекстный API используется относительно редко, поэтому он вызывает меньше ошибок.

благодарныйпредложение атрибута класса, такие баги почти вымерли.Пока конструктор не объявлен явно, все параметры передаются автоматически. Итак, вstate = {}выражение, вы можете получить доступthis.propsтак же какthis.context.