Обработка событий (Handling Events)

Обработка событий с React элементами очень похожа на обработку событий на DOM элементах. Имеются различия в синтаксисе:

  • События React именуются в camelCase, а не в нижнем регистре.
  • С JSX вы передаете функцию в качестве обработчика события, а не строку.

Например, HTML:

<button onclick="activateLasers()">
  Activate Lasers
</button>

в React немного отличается:

<button onClick={activateLasers}>
  Activate Lasers
</button>

Другое отличие состоит в том, что в React вы не можете вернуться false, чтобы предотвратить поведение по умолчанию. Вы должны вызвать preventDefault в явном виде. Например, для простого фрагмента HTML, чтобы предотвратить поведение по умолчанию при нажатии на ссылку для открытия новой страницы, вы можете написать:

<a href="#" onclick="console.log('The link was clicked.'); return false">
  Click me
</a>

В React, вместо этого должно быть:

function ActionLink() {
  function handleClick(e) {
    e.preventDefault();
    console.log('The link was clicked.');
  }

  return (
    <a href="#" onClick={handleClick}>
      Click me
    </a>
  );
}

Здесь e представляет собой синтетическое событие. React определяет эти синтетические события в соответствии с W3C спецификацией, так что вам не нужно беспокоиться о совместимости с различными браузерами. Обратитесь к руководству SyntheticEventreference, чтобы узнать больше.

При использовании React, как правило, не нужно вызывать addEventListener для добавления слушателей к элементу DOM после того, как он будет создан. Вместо этого просто обеспечить слушателя, когда элемент изначально отрисованы.

При определении компонента, используя классы ES6, общий шаблон для обработчика событий — он должен быть методом в классе. Например, этот компонент Toggle  отрисовывается как кнопка, которая позволяет переключаться между состояниями  «ON» и «OFF»:

class Toggle extends React.Component {
  constructor(props) {
    super(props);
    this.state = {isToggleOn: true};

    // Это связывание необходимо делать работой `this` в функции обратного вызова
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick() {
    this.setState(prevState => ({
      isToggleOn: !prevState.isToggleOn
    }));
  }

  render() {
    return (
      <button onClick={this.handleClick}>
        {this.state.isToggleOn ? 'ON' : 'OFF'}
      </button>
    );
  }
}

ReactDOM.render(
  <Toggle />,
  document.getElementById('root')
);

Попробовать на CodePen.

Вы должны быть осторожны, определяя значении this в обратных вызовах JSX. В JavaScript, методы класса не связаны по умолчанию. Если вы забыли связать this.handleClick и передать его в onClick, this при вызове функции будет undefined.

Это не специфическое для React поведение; это часть того, как функции работают в JavaScript. Как правило, если вы обращаетесь к методу без () после него, подобно onClick={this.handleClick}, вы должны связать этот метод.

Если вызовы bind  вас раздражают, есть два способа как обойти эту проблему. Если вы используете экспериментальный синтаксис инициализатора свойств , вы можете использовать инициализаторы для корректного связывания с функциями обратного вызова (callbacks):

class LoggingButton extends React.Component {
  // Этот синтаксис обеспечивает `this` связанным в handleClick.
  // Предупреждение: это *экспериментальный* синтаксис.
  handleClick = () => {
    console.log('this is:', this);
  }

  render() {
    return (
      <button onClick={this.handleClick}>
        Click me
      </button>
    );
  }
}

Этот синтаксис включен по умолчанию в  Создание React приложения (Create React App).

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

class LoggingButton extends React.Component {
  handleClick() {
    console.log('this is:', this);
  }

  render() {
    // Этот синтаксис сохраняет `this` связанным с handleClick
    return (
      <button onClick={(e) => this.handleClick(e)}>
        Click me
      </button>
    );
  }
}

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