React упрощает обработку событий декларативным способом, упрощая добавление прослушивателей событий и управление взаимодействиями пользователя в вашем приложении. К основным особенностям обработки событий в React можно отнести следующие:
Декларативность: события указываются непосредственно в JSX с использованием синтаксиса camelCase
Синтетические события: React оборачивает собственные события в кроссбраузерную оболочку для обеспечения согласованности
Встроенная и внешняя обработка: обработчики событий могут быть встроенными или определены как отдельные функции
Обработка событий элементов в React во многом похожа на обработку событий элементов DOM с помощью обычного JavaScript. В то же время есть небольшие отличия:
События в React используют camelCase (в стандартном html "onclick", в React - "onClick")
В JSX в обработчик события передается функция компонента, а не строка
В React можно применять разные способы определения и вызова событий. Возьмем простейшую задачу - обработка нажатия кнопки:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>METANIT.COM</title>
</head>
<body>
<div id="app"></div>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<script type="text/babel" data-type="module">
import React from "https://esm.sh/react@19?dev";
import ReactDOM from "https://esm.sh/react-dom@19/client?dev";
// обработчик нажатия кнопки
function press() { console.log("Button clicked!");}
ReactDOM.createRoot(
document.getElementById("app")
)
.render(
<button onClick={press}>Click</button>
);
</script>
</body>
</html>
Здесь определена функция press, которая выполняет роль обработчика события нажатия кнопки. И у кнопки устанавливаем атрибут onClick, передавая ему в фигурных скобках обработчик:
<button onClick={press}>Click</button>
В итоге при нажатии в консоли браузера отобразится соответствующее сообщение:
При этом мы могли бы опредлить все действия непосредственно в компоненте без создания внешней функции обработчика события:
<button onClick={()=>{console.log("Clicked");}}>Click</button>
Обратите внимание, что в этом случае обработчик задается как стрелочная функция - onClick={()=>{console.log("Clicked");}}, а не просто onClick={console.log("Clicked")}
Если обработчик события принимает некоторые параметры, то для передачи параметров также применяется стрелочная функция:
function press(message) { console.log(message);}
ReactDOM.createRoot(
document.getElementById("app")
)
.render(
<button onClick={()=>{press("Clicked!")}}>Click</button>
);
Теперь посмотрим, как определить обработчики событий в компонентах.
Использование событий в функциональных компонентах несколько проще. Так, перепишем предыдущий код в компонент в функциональном стиле:
function ClickButton(props) {
function press(){
console.log("Hello METANIT.COM!");
}
return <button onClick={press}>Click</button>;
}
Здесь в принципе все то же самое, только теперь код JSX и обработчик события инкапсулированы в рамках одного компонента. Использование функционального компонента:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>METANIT.COM</title>
</head>
<body>
<div id="app"></div>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<script type="text/babel" data-type="module">
import React from "https://esm.sh/react@19?dev";
import ReactDOM from "https://esm.sh/react-dom@19/client?dev";
function ClickButton(props) {
function press(){
console.log("Hello METANIT.COM!");
}
return <button onClick={press}>Click</button>;
}
ReactDOM.createRoot(
document.getElementById("app")
)
.render(
<ClickButton />
);
</script>
</body>
</html>
При определении событий в классах-компонентах распространенный подход заключается в установке привязки события в конструкторе компонента:
class ClickButton extends React.Component {
constructor(props) {
super(props);
this.press = this.press.bind(this);
}
press(){
console.log("Hello METANIT.COM!");
}
render() {
return <button onClick={this.press}>Click</button>;
}
}
Главная сложность при использовании событий в компонентах-классах - это работа с ключевым словом this, которое указывает на текущий
объект, в данном случае компонент. По умолчанию в функцию обработчика не передается текущий объект, поэтому this будет иметь значение undefined. И ни к каким свойствам и методам компонента
через this мы обратиться не сможем. И чтобы в метод press корректно передавалась ссылка на текущий объект через this, в конструкторе класса
прописывается вызов:
this.press = this.press.bind(this);
И также стоит отметить, что при определении конструктора компонента в нем должен вызываться конструктор базового класса, в который передается объект props.
Использование класса-компонента на веб-странице аналогично:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>METANIT.COM</title>
</head>
<body>
<div id="app"></div>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<script type="text/babel" data-type="module">
import React from "https://esm.sh/react@19?dev";
import ReactDOM from "https://esm.sh/react-dom@19/client?dev";
class ClickButton extends React.Component {
constructor(props) {
super(props);
this.press = this.press.bind(this);
}
press(){
console.log("Hello METANIT.COM!");
}
render() {
return <button onClick={this.press}>Click</button>;
}
}
ReactDOM.createRoot(
document.getElementById("app")
)
.render(
<ClickButton />
);
</script>
</body>
</html>
Однако есть и другие способы определения и вызова события. Например, определение обработчика в виде публичного поля компонента, которое указывает на стрелочную функцию.
class ClickButton extends React.Component {
press = () => {
console.log("Hello React!")
}
render() {
return <button onClick={this.press}>Click</button>;
}
}
Либо мы можем определить функцию обработчика события как обычный метод класса, а вызывать с помощью стрелочной функции:
class ClickButton extends React.Component {
press(){
console.log("Hello METANIT.COM!");
}
render() {
return <button onClick={() => this.press()}>Click</button>;
}
}
Однако в случае с использованием стрелочной функции есть вероятность столкнуться с проблемой производительности, если функция обработчика передается через свойства props вложенным компонентам. Так как обработчик события будет создаваться каждый раз заново при каждом рендеринге компонента, что может привести к дополнительному повторному рендерингу вложенных компонентов, без которого можно было бы обойтись. Поэтому использование конструктора является более предпочтительной практикой.
React использует концепцию SyntheticEvent - специальных объектов, которые представляют собой обертки для объектов событий, передаваемых в функцию события. И используя такой объект, мы можем получить в обработчике события всю информацию о событии:
function ClickButton(props) {
function press(e){
console.log(e); // выводим информацию о событии
console.log("Hello METANIT.COM!");
}
return <button onClick={press}>Click</button>;
}
Параметр e - это и есть информация о событии, которая передается в обработчик системой и которую мы можем использовать при обработке.
Аналогичный пример для класса-компонента:
class ClickButton extends React.Component {
constructor(props) {
super(props);
this.press = this.press.bind(this);
}
press(e){
console.log(e); // выводим информацию о событии
console.log("Hello METANIT.COM!");
}
render() {
return <button onClick={this.press}>Click</button>;
}
}
Если необходимо передать в обработчик события некоторые аргументы, то в этом случае можно вызвать обработчик через стрелочную функцию:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>METANIT.COM</title>
</head>
<body>
<div id="app"></div>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<script type="text/babel" data-type="module">
import React from "https://esm.sh/react@19?dev";
import ReactDOM from "https://esm.sh/react-dom@19/client?dev";
function PrintButton(props) {
function print(name, age){
console.log(`Name ${name} Age: ${age}`);
}
return <div>
<button onClick={() => print("Bob", 23)}>Print Bob</button>
<button onClick={() => print("Tom", 36)}>Print Tom</button>
</div>;
}
ReactDOM.createRoot(
document.getElementById("app")
)
.render(
<PrintButton />
);
</script>
</body>
</html>
Аналогичный пример для класса-компонента:
class PrintButton extends React.Component {
constructor(props) {
super(props);
this.print = this.print.bind(this);
}
print(name, age){
console.log(`Name ${name} Age: ${age}`);
}
render() {
return <div>
<button onClick={() => this.print("Bob", 23)}>Print Bob</button>
<button onClick={() => this.print("Tom", 36)}>Print Tom</button>
</div>;
}
}