> Как добавить обработчик события на DOM-элемент в React? (React)

Уровень: senior · Роль: frontend · Категория: Технические вопросы

Компании: Сбер

Стек: React

> Пример ответа

Короткий ответ

В React обработчики событий добавляются через JSX-атрибуты в camelCase-нотации, например onClick={handler}. В отличие от нативного DOM, React использует делегирование событий на корневой контейнер и синтетические события (SyntheticEvent) для кросс-браузерной совместимости. Прямое использование addEventListener в React антипаттерн, за исключением случаев работы с внешними библиотеками или событиями, не поддерживаемыми React (например, события скролла на window).

Подробное объяснение

React предоставляет декларативный API для обработки событий, который автоматически управляет подпиской и отпиской при монтировании/размонтировании компонента. Основные отличия от нативного подхода:

  • Синтаксис: атрибуты пишутся в camelCase (onClick, onChange), передаётся функция, а не строка
  • SyntheticEvent: React оборачивает нативное событие в кросс-браузерную обёртку с пулом объектов для оптимизации производительности
  • Делегирование: все обработчики привязываются к корневому элементу React-дерева, а не к конкретным DOM-узлам
  • Автоматическое управление: React сам добавляет и удаляет обработчики при обновлении компонента

Для событий, не поддерживаемых React (например, transitionend, animationstart), или при работе с порталами и внешними библиотеками допустимо использовать useEffect с addEventListener, но с обязательной очисткой в return-функции.

На практике

В production-коде следует придерживаться нескольких правил:

  • Использовать стрелочные функции только если нужен доступ к замыканию, иначе выносить обработчик в метод класса или useCallback
  • Для передачи аргументов использовать коллбэк: onClick={() => handleClick(id)} - это создаёт новую функцию при каждом рендере, но для простых случаев допустимо
  • При работе с формами предпочитать onChange вместо onInput для единообразия
  • Для событий клавиатуры использовать onKeyDown, а не onKeyPress (deprecated)
  • В классовых компонентах не забывать bind методов в constructor или использовать class properties

Пример кода

JSX
// Функциональный компонент с обработчиком
function Button({ onClick, label }) {
const handleClick = useCallback((e) => {
e.preventDefault();
console.log('Clicked:', label);
onClick?.(e);
}, [label, onClick]);
return <button onClick={handleClick}>{label}</button>;
}
// Использование addEventListener для внешнего события
function ScrollWatcher() {
useEffect(() => {
const handleScroll = () => {
console.log('Scrolled');
};
window.addEventListener('scroll', handleScroll);
return () => window.removeEventListener('scroll', handleScroll);
}, []);
return <div>Scroll event listener attached</div>;
}

Как отвечать на собеседовании

Начни с прямого ответа: через JSX-атрибуты в camelCase. Затем объясни концепцию SyntheticEvent и делегирования - это покажет понимание внутреннего устройства React. Упомяни, что прямое использование addEventListener оправдано только для событий вне системы React или при интеграции с библиотеками. Приведи пример с useEffect и очисткой. Избегай излишних деталей про пул событий, если не спрашивают. Закончи коротким резюме: React упрощает управление событиями, но требует понимания его абстракций.

Что проверяет интервьюер

  • Понимание разницы между нативными событиями и синтетическими в React
  • Знание декларативного подхода и автоматического управления жизненным циклом обработчиков
  • Умение обосновать, когда нужно отходить от стандартного API React
  • Понимание проблем производительности (создание новых функций при каждом рендере)
  • Навыки работы с хуками (useEffect, useCallback) для управления событиями

Типичные ошибки

  • Использование addEventListener внутри компонента без очистки в useEffect - приводит к утечкам памяти
  • Передача вызова функции вместо ссылки: onClick={handleClick()} - выполняется при рендере
  • Забывание camelCase: onclick, onchange - не сработает
  • Использование return false для предотвращения поведения по умолчанию - в React нужно вызывать e.preventDefault()
  • Создание новых функций в render без useCallback для часто обновляемых компонентов - лишние ререндеры дочерних элементов

> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?

Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью