Обработка событий с 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')
);
Вы должны быть осторожны, определяя значении 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
визуализируется. В большинстве случаев, это прекрасно. Однако, если этот обратный вызов передается в качестве свойства для низших компонентов, эти компоненты могут сделать дополнительный повторный рендеринг (повторную отрисовку). Как правило, мы рекомендуем выполнять связывание в конструкторе, чтобы избежать такого рода проблем с производительностью.