Перевод официальной документации библиотеки React.js на русском языке.

Оглавление:


1 — Часть первая — Установка
2 — Часть вторая — Внедрение JSX
3 — Часть третья — Отрисовка элементов
4 — Часть четвертая — Компоненты и свойства
5 — Часть пятая — Состояние и жизненный цикл
6 — Часть шестая — Обработка событий
7 — Часть седьмая — Условный рендеринг
8 — Часть восьмая — Списки и ключи
9 — Часть девятая (скоро)

Обработка событий


Обработка событий с элементами React очень схожа с обработкой событий с элементами DOM.

Существует несколько синтаксических различий:

Названия событий React создаются с помощью camelCase, а не lowercase. С 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 spec поэтому вам не стоит беспокоиться о кросс-браузерной совместимости.

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

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

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

    // This binding is necessary to make `this` work in the callback
    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.

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

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

Если вы не хотите отправлять сигналы в bind, то есть еще два возможных действия. Если вы используете экспериментальный плагин property initializer syntax, то вы можете использовать инициализаторы реализуемых свойств, чтобы правильно связать обратные вызовы:

class LoggingButton extends React.Component {
  // This syntax ensures `this` is bound within handleClick.
  // Warning: this is *experimental* syntax.
  handleClick = () => {
    console.log('this is:', this);
  }

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

Данный синтаксис в Create React App включен по умолчанию. Если вы не используете инициализаторы свойств, вы можете применить стрелочную функцию (arrow function) в обратных сигналов:

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

  render() {
    // This syntax ensures `this` is bound within handleClick
    return (
      <button onClick={(e) => this.handleClick(e)}>
        Click me
      </button>
    );
  }
}

Проблема с таким синтаксисом состоит в том, что другой обратный сигнал создается каждый раз, когда выводится LoggingButton. Чаще всего, это нормальное явление. Однако если обратные сигналы передаются как свойства для нижних компонентов, то такие компоненты могут произвести повторное демонтирование. Чаще всего, мы советуем производить связывание в конструкторе, чтобы избежать подобных проблем с производительностью.
Поделиться с друзьями
-->

Комментарии (14)


  1. lekzd
    01.12.2016 12:19
    +11

    Скриншот шаблона Wordpress в тему конечно


  1. crocodile2u
    01.12.2016 13:29

    Еще вариант забиндить this: <button onClick={this.handleClick.bind(this)}>


    1. sdwvit
      01.12.2016 13:40

      И при каждой отрисовке будет выполняться дорогая функция бинд. Тогда уж в конструктор вынести.


    1. murderinc
      01.12.2016 13:49

      Еще вариант использовать статические свойства класса https://babeljs.io/blog/2015/06/07/react-on-es6-plus


    1. faiwer
      01.12.2016 13:54

      .bind каждый раз порождает новый метод. Это не так дёшево, как может показаться. А ещё если передавать таким вот образом метод внутрь вложенных сложных компонентов, то, если я правильно понимаю это, React будет вынужден вызывать .render() у любого компонента, которому был доступен этот метод (через .props). Т.е. принудительный .render() всем "соучастникам" при каждом .render()-е родительского компонента.


      Та же беда и у => функций.


      1. Veikedo
        01.12.2016 13:59

        Насколько знаю, при => используется замыкание на this, а не bind.
        По крайней мере, в typescript


        1. faiwer
          01.12.2016 14:02
          +1

          Принцип работы => не настолько прост, чтобы описать его в двух словах или приравнять к .bind-у. Но в данном случае это не важно, важно то, что любая анонимная функция в методе всякий раз создаётся заново. А это в свою очередь приводит к тому, что .props у дочерних компонентов меняется всегда. И они вынуждены рендериться повторно. Или я что-то путаю? Вроде об этом было даже в документации.


          1. Veikedo
            01.12.2016 14:06

            Да, верно, спасибо.


          1. rogov_dmitry
            02.12.2016 01:44

            Ого, большое спасибо за озвучивание этого момента. В голову не приходило такое.

            А не ткнете в каком месте в доках об этом говорится?


      1. faiwer
        01.12.2016 14:04

        The problem with this syntax is that a different callback is created each time the LoggingButton renders. In most cases, this is fine. However, if this callback is passed as a prop to lower components, those components might do an extra re-rendering. We generally recommend binding in the constructor to avoid this sort of performance problem.

        https://facebook.github.io/react/docs/handling-events.html


    1. koutsenko
      01.12.2016 14:56

      Или для простых случаев использовать Stateless Functional Components.
      Там this совсем не нужен — область видимости всегда указывает на сам компонент.


  1. n0ne
    02.12.2016 11:49

    А можно небольшую просьбу? Сделайте оглавление по разделам, а не номерам частей… людям проще ориентироваться будет, куда переходить, если что
    Спасибо.


  1. foxmuldercp
    02.12.2016 19:37

    Чаще всего, мы советуем производить связывание в конструкторе, чтобы избежать подобных проблем с производительностью.

    Эм, а можно пример кода?


    1. html_manpro
      02.12.2016 19:54
      +1

      constructor(props) {
       super(props);
       this.addTodo = this.addTodo.bind(this);
      }
      


       <button
       className='btn btn-primary'
       onClick={this.addTodo}
       >
      Add todo</button>