> Как добавить обработчик события на 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 для часто обновляемых компонентов - лишние ререндеры дочерних элементов
> Похожие задачи по frontend
Какой роутер используется в React: нативный или сторонний
Что происходит после создания work tree и current tree в React
Является ли изменение пропсов триггером ререндеринга в React
Что такое pure component и как создать его на примере функционального компонента в React
> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?
Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью