Как избежать создания ссылок this в ES6: const that = this, когда область вложена в React

Я читаю руководство по стилю javascript air-bnb, и в нем говорится, что этого делать не следует:

23.5 Не сохраняйте ссылки на это. Используйте стрелочные функции или Function#bind.

// bad
function foo() {
  const self = this;
  return function () {
    console.info(self);
  };
}

// bad
function foo() {
  const that = this;
  return function () {
    console.info(that);
  };
}

// good
function foo() {
  return () => {
    console.info(this);
  };
}

Я уже провел некоторое исследование и нашел два ответа здесь, в stackoverflow, но принятый ответ в одном из них заключается в том, что это нельзя обойти:

ES6 избегай этого/я

а другой предлагает использовать привязку, но предлагает использовать функцию генератора.

Вложенная ссылка на this в классах ES6

Я создаю приложение ReactJS, и мне нужно получить доступ к setState из Firebase Promise.

   saveSessionToDB = () => {
        const that = this;
        db.collection("sessions")
          .add({
            props: MyProps
          })
          .then(function(docRef) {
            console.info("Session written with ID: ", docRef.id);
            that.setState({ sessionID: docRef.id });
          })
          .catch(function(error) {
            console.error("Error adding document: ", error);
            that.setState({ sessionError: error });
          });
}

Я старался

const {setState} = this;

а потом

setState({sessionID:docRef.id});

но я получаю сообщение об ошибке.

Я безуспешно пытался связать saveSessionToDB в конструкторе, даже если это функция стрелки.

Есть ли другой способ сделать это или я должен просто принять, что иногда мне все равно придется писать const that = this?

Почему бы вам просто не использовать стрелочные функции?

Roberto Zvjerković 03.07.2019 12:01

Вы можете напомнить им о бритва Хитченса. Почему это плохо?

RobG 03.07.2019 12:01

@ritaj это функция стрелки.

guergana 03.07.2019 12:02

@RobG почти все правила ESLint не имеют «доказательства» того, что они плохие, но в основном являются стандартами кодирования. Хорошо сохранять их, плохо отклоняться, даже если вы можете добиться того же самого с другим кодом/синтаксисом/форматированием.

VLAZ 03.07.2019 12:03

@guergana не то, на что ты переходишь .then

VLAZ 03.07.2019 12:03
.then(function(docRef) {} ) это не функция стрелки.
Roberto Zvjerković 03.07.2019 12:03

да, только что заметил. Спасибо!

guergana 03.07.2019 12:06

@VLAZ — да, смотрите документация. ESLint не предписывает, что «хорошо» или «плохо», это просто набор правил, которые можно использовать для проверки стиля кодирования, т. Е. То, что у него есть правило, не означает, что соблюдение этого правила является хорошей идеей в целом. Документация включает рекомендации, когда не следует использовать определенные правила (например, недействительный-это).

RobG 03.07.2019 12:18

@RobG, это ... то, что я сказал. Правила ESLint предназначены только для обеспечения соблюдения стандартов кодирования. Следовательно, это не «хорошо» и не «плохо».

VLAZ 03.07.2019 12:21

@VLAZ - конечно, упустил твою мысль. :-) Но это подтверждает, что Airbnb должен объяснить, почему это и себя не следует использовать (мне действительно все равно, я просто думаю, что они должны объяснить, почему они настаивают на определенном стиле кодирования).

RobG 03.07.2019 12:25
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
2
10
1 040
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Вы также должны использовать функции стрелок для then и catch:

saveSessionToDB = () => {
  db.collection("sessions")
    .add({ props: MyProps })
    .then((docRef) => {
      console.info("Session written with ID: ", docRef.id);
      this.setState({ sessionID: docRef.id });
    })
    .catch((error) => {
      console.error("Error adding document: ", error);
      this.setState({ sessionError: error });
    });
}

Причина, по которой стрелочные функции полезны, заключается в том, что они не имеют собственного контекста this (или arguments), поэтому они берут this из своего внешнего лексического окружения. Вот почему вы можете использовать this компонента внутри функции стрелки.

Используйте стрелочные функции для внутренних функций:

.then(docRef => {
  console.info("Session written with ID: ", docRef.id);
  this.setState({ sessionID: docRef.id });
})
.catch(error => {
  console.error("Error adding document: ", error);
  this.setState({ sessionError: error });
});

Или используйте bind:

.then(function(docRef) {
  console.info("Session written with ID: ", docRef.id);
  that.setState({ sessionID: docRef.id });
}.bind(this))
.catch(function(error) {
  console.error("Error adding document: ", error);
  that.setState({ sessionError: error });
}.bind(this));

В промисах, которые используются на экранах/компонентах и ​​даже, в основном за пределами синтаксиса реакции в методе then() и catch(), вы обычно отправляете функцию стрелки (в контексте выборки ничего не стоит), поэтому вы сохраняете контекст снаружи (В данном случае контекст React.Component).

В вашем случае всего с двумя фиксами (стрелочная функция и что к этому) все работает:

saveSessionToDB = () => {
        const that = this;
        db.collection("sessions")
          .add({
            props: MyProps
          })
          .then((docRef) => { // arrow function
            console.info("Session written with ID: ", docRef.id);
            this.setState({ sessionID: docRef.id }); // that => this
          })
          .catch((error) => { // arrow function
            console.error("Error adding document: ", error);
            this.setState({ sessionError: error }); // that => this
          });
}

Другие вопросы по теме

ReactJs — каждый дочерний элемент в списке должен иметь уникальную «ключевую» опору
Должна ли функция реактивного субрендеринга возвращать контент только в одном внешнем теге?
Столкнулся с множеством проблем при установке семантического пользовательского интерфейса в проекте реагирования
Хранение элементов внутри массива в состоянии
Динамическое изменение значения индикатора выполнения Bootstrap в ответ
Реагировать на стилизованный компонент, анимация: инвертировать положение двух div
Могу ли я создать два реагирующих приложения в одном весеннем проекте?
Как отображать повторно используемые компоненты по одному в reactjs?
Не удается подключить хранилище избыточности к компонентам сематического диммера пользовательского интерфейса
Необработанное отклонение (TypeError): невозможно прочитать свойство «0» неопределенного