Обработка событий в React
Обработка событий с React-элементами очень схожа с обработкой событий с DOM-элементами
Существует несколько отличий в синтаксисе:
- Названия событий в React создаются с помощью camelCase, а не lowercase.
- С JSX вы передаете функцию как обработчик события, а не строку.
Например:
Another difference is that you cannot return false to prevent default behavior in React. You must call preventDefault explicitly. For example, with plain HTML, to prevent the default link behavior of opening a new page, you can write:
Еще одно отличие заключается в том, что в React Вы не можете вернуть false, чтобы предотвратить поведение по умолчанию. Вы должны явно вызвать preventDefault. Например, в HTML, чтобы предотвратить по умолчанию открытие по ссылке новой страницы, вы можете написать:
<a href="#" onclick="console.log('Ссылка была нажата'); return false">
Нажми меня
</a>
В React вы должны написать следующее:
function ActionLink() {
function handleClick(e) {
e.preventDefault();
console.log('Ссылка была нажата');
}
return (
<a href="#" onClick={handleClick}>
Нажми меня
</a>
);
}
Здесь, e - это синтетическое событие. React определяет эти события в соответствии со спецификацией W3C, поэтому вам не нужно беспокоиться о кросс-браузерной совместимости (см. справочное руководство SyntheticEvent, чтобы узнать больше).
При использовании React вам, обычно, не нужно вызывать addEventListener, чтобы добавить обработчики событий к DOM-элементу после его создания. Вместо этого, просто выполните обработчик когда элемент впервые отображается.
When you define a component using an ES6 class, a common pattern is for an event handler to be a method on the class. For example, this Toggle component renders a button that lets the user toggle between "ON" and "OFF" states:
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')
);
Try it on CodePen.
You have to be careful about the meaning of this in JSX callbacks. In JavaScript, class methods are not bound by default. If you forget to bind this.handleClick and pass it to onClick, this will be undefined when the function is actually called.
This is not React-specific behavior; it is a part of how functions work in JavaScript. Generally, if you refer to a method without () after it, such as onClick={this.handleClick}, you should bind that method.
If calling bind annoys you, there are two ways you can get around this. If you are using the experimental property initializer syntax, you can use property initializers to correctly bind callbacks:
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>
);
}
}
This syntax is enabled by default in Create React App.
If you aren't using property initializer syntax, you can use an arrow function in the callback:
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>
);
}
}
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 or using the property initializer syntax, to avoid this sort of performance problem.