Оригинальный адрес:Why Do We Write super(props) ? Оригинальный автор:Dan Abramov Переводчик:Washington Hua
я слышалаHooksВ последнее время было жарко. По иронии судьбы, я хочу начать этот блог с нескольких интересных историй о компонентах классов. как! (Кожа очень довольна)
Эти подводные камни не помешают вашему эффективному использованию React, но если вы готовы углубиться в работу, стоящую за ним, вы найдете их очень интересными.
Это первый.
Я писал всю свою жизньsuper(props)
Гораздо больше, чем я думал
class Checkbox extends React.Component {
constructor(props) {
super(props);
this.state = { isOn: true };
}
// ...
}
Конечно,class fields proposalПозвольте нам пропустить этот ритуал.
class Checkbox extends React.Component {
state = { isOn: true };
// ...
}
Этот синтаксис был добавлен, когда React 0.13 добавил поддержку чистых классов в 2015 году.строить планыОпределение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) {
// 🔴 这时候还不能使用 `this`
super(props);
// ✅ 现在开始可以了
this.state = { isOn: true };
}
// ...
}
JavaScript заставляет вас использоватьthis
Есть веская причина запускать конструктор родительского класса раньше. Рассмотрим такую структуру класса:
class Person {
constructor(name) {
this.name = name;
}
}
class PolitePerson extends Person {
constructor(name) {
this.greetColleagues(); // 🔴 这是不允许的,下面会解释原因
super(name);
}
greetColleagues() {
alert('Good morning folks!');
}
}
Представьте, если звонитеsuper
перед использованиемthis
разрешено. спустя месяц. мы могли бы изменитьgreetColleagues
Добавьте имя человека в сообщение.
greetColleagues() {
alert('Good morning folks!');
alert('My name is ' + this.name + ', nice to meet you!');
}
но мы забылиthis.greetColleagues()
вsuper()
шанс установитьthis.name
звонили раньше.this.name
Это еще даже не определено! Как видите, такой код может быть труден для понимания.
Чтобы избежать этой ловушки,JavaScript требует, чтобы, если вы хотите, в конструкторе использовать толькоthis
, вы должны сначала позвонитьsuper
. Пусть родительский класс делает свое дело! Это ограничение также распространяется на компоненты React, определенные как классы.
constructor(props) {
super(props);
// ✅ 现在可以使用 `this` 了
this.state = { isOn: true };
}
Это оставляет нас с другим вопросом: почемуprops
?
ты можешь подуматьprops
пройти вsuper
необходимо, что делает базовый классReact.Component
может быть инициализированthis.props
:
// React 内部
class Component {
constructor(props) {
this.props = props;
// ...
}
}
очень близко - на самом деле,он делает именно это.
Однако даже при вызовеsuper()
нет входящихprops
параметры, вы все еще можетеrender
и другие способы доступаthis.props
. (если не верите, можете попробовать сами)
Каков принцип? фактическиReact снова устанавливает экземпляр сразу после вызова вашего конструктораprops
:
// React 内部
const instance = new YourComponent(props);
instance.props = props;
Поэтому, даже если вы забудете поставитьprops
входящийsuper()
, React все равно установит их постфактум. Для этого есть причина.
Когда React добавил поддержку классов, он не просто добавил поддержку ES6, он хотел поддерживать максимально широкую абстракцию классов. из-зане уверенClojureScript, CoffeeScript, ES6, Fable, Scala.js, TypeScript или другие решения больше подходят для определения компонентов, React необходим для вызоваsuper()
Намеренно не выражая позицию.
Значит ли это, что вы можете просто написатьsuper()
вместоsuper(props)
?
Может быть, нет, потому что это все еще беспокоит. Правда, React установит его после запуска вашего конструктораthis.props
. но вsuper
Вызывается до конца конструктора,this.props
все еще не определено.
// React 内部
class Component {
constructor(props) {
this.props = props;
// ...
}
}
// 你的代码
class Button extends React.Component {
constructor(props) {
super(); // 😬 我们忘了传入 props
console.log(props); // ✅ {}
console.log(this.props); // 😬 undefined
}
// ...
}
Если это произойдет с какой-то функцией, вызываемой из конструктора, отладка будет более проблематичной.Вот почему я рекомендую всегда использоватьsuper(props)
, даже если это не обязательно:
class Button extends React.Component {
constructor(props) {
super(props); // ✅ 我们传了 props
console.log(props); // ✅ {}
console.log(this.props); // ✅ {}
}
// ...
}
Такой способ письма гарантирует, чтоthis.props
Даже если он установлен до возврата конструктора.
И последний момент, который может заинтересовать давних пользователей React.
Вы могли заметить, что когда вы используете Context API в классе (либо старый синтаксис, либо современный синтаксис, добавленный в React 16.6), контекст передается в качестве второго параметра конструктора.
Так почему бы нам не написатьsuper(props, context)
Шерстяная ткань? Конечно, мы могли бы это сделать, но контекст используется не так часто, так что эта ловушка не такая уж большая проблема.
С выпуском предложения полей классов эта проблема больше не существует.Даже если конструктор не вызывается явно, все параметры передаются автоматически. Это позволяет такие вещи, какstate = {}
Такие выражения можно цитировать напрямую, когда это необходимо.this.props.
илиthis.context
.
В Hooks у нас даже нетsuper
илиthis
. Мы обсудим эту тему в другой день.