Почему мы пишем super(props)?

внешний интерфейс JavaScript React.js CoffeeScript
  • Оригинальный адрес: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. Мы обсудим эту тему в другой день.