Почему мы добавляем super(props)?

React.js

я слышалаHooksстал новым фокусом. Тем не менее, я хочу представить интересную часть компонента объявления класса через этот блог. как насчет?

Следующее не улучшит ваши навыки React. Но когда вы углубитесь в то, как все работает, вы обнаружите радость, которую они приносят.

Сначала рассмотрим первый пример.


я написалsuper(props)Количество раз намного больше, чем я думал:

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

Конечно,class fields proposal(предложение JS) заставляет нас пропустить этот процесс:

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

Это синтаксис класса, поддерживаемый в React 0.13 в 2015 году.planned. существуетclass fieldsПрежде чем появится эта более разумная альтернатива, утверждениеconstructorи позвониsuper(props)Он всегда использовался как временное решение.

Но перед этим вернемся к примеру только для ES2015:

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

зачем звонитьsuper? мы можемНе делайтеназови это? Если мы должны вызвать его, вызовите его, не проходяpropsЧто случится? Будут ли еще параметры? Приходите и найдите ответ вместе.


JavaScript,superЯвляется ссылкой на конструктор родительского класса. (В нашем случае это указывает наReact.Component)

Очень важно, что вы не можете использовать его в конструкторе до вызова конструктора родительского классаthisДа, JavaScript не позволяет вам сделать это:

class Checkbox extends React.Component {
  constructor(props) {
    // 🔴 Can’t use `this` yet
    super(props);
    // ✅ Now it’s okay though
    this.state = { isOn: true };
  }
  // ...
}

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

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

class PolitePerson extends Person {
  constructor(name) {
    this.greetColleagues(); // 🔴 This is disallowed, read below why
    super(name);
  }
  greetColleagues() {
    alert('Good morning folks!');
  }
}

предположим вsuperразрешено звонить раньшеthis. Через месяц мы можем бытьgreetColleaguesдобавлен кnameАтрибуты:

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

Однако мы забыли объявитьthis.nameизsuperПеред вызовом метода он был вызванthis.greetColleagues(). так чтоthis.nameсталundefinedположение дел! Как видите, в результате код становится непредсказуемым.

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

  constructor(props) {
    super(props);
    // ✅ Okay to use `this` now
    this.state = { isOn: true };
  }

Есть еще вопрос, почемуprops?


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

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

На самом деле, это почти та же причина, что иточная причина.

Но иногда, даже при звонкеsuperвечныйpropsпараметры, вы по-прежнему можете использоватьrenderи другие методыthis.props. (Если не верите мне, попробуйте сами!)

Как это достигается? Причина в том, что после того, как ваш компонент будет создан, он назначитpropsатрибуты объектов-экземпляров.

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

Так что даже если вы забудетеpropsДатьsuper, React по какой-то причине все равно установит их позже.

Когда React добавил поддержку классов, он не просто добавил поддержку ES6, цель состояла в том, чтобы поддерживать как можно более широкую абстракцию классов. В то время мы были ещене ясноТакие как ClojureScript, CoffeeScript, ES6, Fable, Scala.js, TypeScript или другие решения, как успешно определять компоненты, поэтому React не заботится о том, нужно ли его вызыватьsuper()Да - даже ES6.

Так что можно просто использоватьsuper()заменитьsuper(props)?

лучше не надо. Потому что с этим все еще есть проблемы. Правильно, React может датьthis.propsНазначение. ноthis.propsвызовsuperи пока конструктор не закончитсяundefined:

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

// Inside your code
class Button extends React.Component {
  constructor(props) {
    super(); // 😬 We forgot to pass props
    console.log(props);      // ✅ {}
    console.log(this.props); // 😬 undefined 
  }
  // ...
}

Если это относится к некоторым методам в конструкторе, их будет сложно отлаживать.Это также почему я продолжаю рекомендовать добавлять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или позже добавлено в React 16.6contextTypeAPI,contextбудет передан как второй параметр конструктора).

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

Когда будет предложено поле класса, большинство ям исчезнет. Если конструктор не указан, все параметры будут переданы автоматически. Это позволяет такие вещи, какstate = {}выражение, если необходимоthis.propsилиthis.contextТо же самое будет применяться.

В Hooks нам даже не нужноsuperилиthis. Но это на другой день.

перевести оригиналWhy Do We Write super(props)?