Перевод официальной документации библиотеки 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)
crocodile2u
01.12.2016 13:29Еще вариант забиндить this: <button onClick={this.handleClick.bind(this)}>
sdwvit
01.12.2016 13:40И при каждой отрисовке будет выполняться дорогая функция бинд. Тогда уж в конструктор вынести.
murderinc
01.12.2016 13:49Еще вариант использовать статические свойства класса https://babeljs.io/blog/2015/06/07/react-on-es6-plus
faiwer
01.12.2016 13:54.bind
каждый раз порождает новый метод. Это не так дёшево, как может показаться. А ещё если передавать таким вот образом метод внутрь вложенных сложных компонентов, то, если я правильно понимаю это, React будет вынужден вызывать.render()
у любого компонента, которому был доступен этот метод (через.props
). Т.е. принудительный.render()
всем "соучастникам" при каждом.render()
-е родительского компонента.
Та же беда и у
=> функций
.Veikedo
01.12.2016 13:59Насколько знаю, при
=>
используется замыкание наthis
, а неbind
.
По крайней мере, в typescriptfaiwer
01.12.2016 14:02+1Принцип работы
=>
не настолько прост, чтобы описать его в двух словах или приравнять к.bind
-у. Но в данном случае это не важно, важно то, что любая анонимная функция в методе всякий раз создаётся заново. А это в свою очередь приводит к тому, что.props
у дочерних компонентов меняется всегда. И они вынуждены рендериться повторно. Или я что-то путаю? Вроде об этом было даже в документации.rogov_dmitry
02.12.2016 01:44Ого, большое спасибо за озвучивание этого момента. В голову не приходило такое.
А не ткнете в каком месте в доках об этом говорится?
faiwer
01.12.2016 14:04The 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.
koutsenko
01.12.2016 14:56Или для простых случаев использовать Stateless Functional Components.
Там this совсем не нужен — область видимости всегда указывает на сам компонент.
n0ne
02.12.2016 11:49А можно небольшую просьбу? Сделайте оглавление по разделам, а не номерам частей… людям проще ориентироваться будет, куда переходить, если что
Спасибо.
foxmuldercp
02.12.2016 19:37Чаще всего, мы советуем производить связывание в конструкторе, чтобы избежать подобных проблем с производительностью.
Эм, а можно пример кода?
html_manpro
02.12.2016 19:54+1constructor(props) { super(props); this.addTodo = this.addTodo.bind(this); }
<button className='btn btn-primary' onClick={this.addTodo} > Add todo</button>
lekzd
Скриншот шаблона Wordpress в тему конечно