JSX реквизиты не должны использовать.bind() - как избежать использования bind?

У меня есть контейнер, который мне нужен, чтобы изменить форму пользовательского интерфейса, показывая форму или страницу успеха.

Контейнер имеет state.showSuccess, и мне нужно, чтобы MyFormModule мог вызывать контейнер для изменения состояния.

Приведенный ниже код работает, но я получаю следующее предупреждение:

"JSX реквизиты не должны использовать.bind()"

Как я могу заставить это работать без использования.bind()?

...
const myPage = class extends React.Component {
  state = { showSuccess: false };
  showSuccess() {
   this.setState({
      showSuccess: true,
    });
  }
  render() {
    const { showSuccess } = this.state;
    if (showSuccess) {...}
    ....
    <MyFormModule showSuccess={this.showSuccess.bind(this)} />

3 ответа

Решение

Сначала вы должны понять, ПОЧЕМУ это плохая практика.

Основная причина здесь в том, что .bind возвращает ссылку на новую функцию.
Это будет происходить на каждом render вызов, который может привести к падению производительности.

У вас есть 2 варианта:

  1. Используйте конструктор для bind ваши обработчики (это будет выполняться только один раз).

    constructor(props) {
      super(props);
      this.showSuccess = this.showSuccess.bind(this);
    }
    
  2. Или создайте ваши обработчики с помощью функций стрелок, чтобы они использовали лексический контекст для thisследовательно, вам не нужно bind их вообще ( вам понадобится плагин babel):

    showSuccess = () => {
      this.setState({
        showSuccess: true,
      });
    }
    

Вы не должны использовать этот шаблон (как предлагали другие):

showSuccess={() => this.showSuccess()}

Потому что это также создаст новую функцию для каждого рендера.
Таким образом, вы можете обойти предупреждение, но вы все еще пишете свой код с плохой практикой.

Из документов ESLint:

Функция связывания или стрелка в опоре JSX создаст совершенно новую функцию для каждого рендера. Это отрицательно сказывается на производительности, так как приводит к тому, что сборщик мусора будет вызываться больше, чем необходимо. Это также может привести к ненужным повторным визуализациям, если совершенно новая функция передается в качестве реквизита компоненту, который использует проверку равенства ссылок на реквизит для определения необходимости обновления.

Используйте функцию стрелки при определении showSuccess

showSuccess = () => {
  this.setState({
    showSuccess: true,
  });
} 

Используйте функцию стрелки, так как они автоматически наследуют this контекст, где они определены.

showSuccess={() => this.showSuccess()}

Вот ссылка на документацию Facebook на эту тему, в которой этот метод указан как решение. Интересно, что они также перечисляют использование .bind в опоре в качестве одного из решений, хотя оно и выдает предупреждение при фактическом использовании.

Из этой документации вы заметите, что это потенциальная проблема с производительностью, так как функция будет воссоздана при каждом рендере:

Замечания:

Использование функции стрелки в рендере создает новую функцию каждый раз при рендеринге компонента, что может влиять на производительность (см. Ниже).

Но также по той же ссылке:

Можно ли использовать функции стрелок в методах рендеринга? В общем, да, это нормально, и часто это самый простой способ передать параметры в функции обратного вызова.

Если у вас есть проблемы с производительностью, обязательно оптимизируйте!

Поэтому я бы сказал, что если ваш компонент будет выполнять рендеринг очень часто, вам следует использовать одно из других решений: связать в конструкторе или сначала определить метод с помощью функции стрелки. Но если нет, используйте любой метод, который кажется вам наиболее чистым.

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