> Где повесить обработчик клика для кнопок при маппинге массива в React? (React)
Уровень: senior · Роль: frontend · Категория: Технические вопросы
Компании: Cyber Interactive
Стек: React
> Пример ответа
Короткий ответ
Обработчик клика для кнопок при маппинге массива в React следует вешать непосредственно на элемент кнопки внутри map, передавая уникальный идентификатор элемента в замыкание. Это стандартный и производительный подход. Избегайте inline-стрелочных функций в JSX без мемоизации, если это не критично для производительности. Для оптимизации используйте useCallback с передачей id.
Подробное объяснение
При маппинге массива в React каждый элемент рендерится как отдельный компонент или JSX-узел. Обработчик клика должен быть привязан к конкретному элементу массива, чтобы знать, какой именно элемент был нажат. Основные варианты:
-
Inline-функция в JSX:
onClick={() => handleClick(item.id)}- самый простой, но создаёт новую функцию при каждом рендере. Для большинства случаев это приемлемо, так как React оптимизирует повторные рендеры. -
Мемоизированный обработчик с useCallback: если массив большой или компонент часто ререндерится, можно создать обработчик с замыканием на id. Однако useCallback сам по себе не решает проблему создания новых функций - нужно правильно указать зависимости.
-
Вынос обработчика в отдельный компонент: для сложных списков с анимациями или большим количеством элементов эффективнее создать отдельный компонент для элемента списка и передавать обработчик через props. Это позволяет React точнее управлять ререндерами.
Ключевой момент - обработчик должен иметь доступ к идентификатору или индексу элемента. Никогда не используйте индекс массива как ключ и не полагайтесь на него в обработчике, если массив может изменяться.
На практике
Для типового проекта с формой или списком задач достаточно inline-функции. Для таблиц с сотнями строк или динамических списков с частыми обновлениями - выносите элемент в отдельный компонент с React.memo. Для критичных по производительности случаев используйте data-атрибуты и делегирование событий на родителе, но это редко оправдано в React.
Пример кода
JSX// Простой случай - inline-функцияfunction TodoList({ items, onToggle }) {return (<ul>{items.map(item => (<li key={item.id}><button onClick={() => onToggle(item.id)}>{item.text}</button></li>))}</ul>);}// Оптимизированный вариант с отдельным компонентомconst TodoItem = React.memo(({ item, onToggle }) => {return (<li><button onClick={() => onToggle(item.id)}>{item.text}</button></li>);});function TodoListOptimized({ items, onToggle }) {return (<ul>{items.map(item => (<TodoItem key={item.id} item={item} onToggle={onToggle} />))}</ul>);}
Как отвечать на собеседовании
Начните с прямого ответа - обработчик вешается на кнопку внутри map. Затем поясните trade-off между простотой inline-функции и производительностью мемоизации. Упомяните, что для большинства реальных приложений inline-функция достаточна. Покажите понимание, когда нужна оптимизация: большие списки, частые ререндеры, анимации. Не забудьте про ключи - используйте уникальный id, а не индекс.
Что проверяет интервьюер
Интервьюер оценивает понимание жизненного цикла React-компонентов, механизма ререндеров и оптимизации производительности. Важно показать, что вы умеете выбирать правильный уровень абстракции: не усложнять там, где не нужно, но знать, как оптимизировать при необходимости. Также проверяется знание замыканий и работы с событиями в JSX.
Типичные ошибки
- Использование индекса массива как ключа и в обработчике - приводит к багам при изменении списка.
- Передача обработчика без мемоизации в компонент, обёрнутый в React.memo - мемоизация теряет смысл.
- Создание обработчика с useCallback без правильных зависимостей - ведёт к stale closure.
- Делегирование событий на контейнере списка через data-атрибуты в React - противоречит декларативному подходу и усложняет код без веской причины.
> Похожие задачи по frontend
Что будет, если передать в React diff div без key
Насколько комфортно работать с Angular и React при переходе с Angular на React
Будет ли middleware блокировать показ страницы пока useSWR не отработает
Как работает useState в Next.js и является ли состояние глобальным или локальным для страницы
> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?
Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью