> Как реализовать добавление и удаление кнопок с уникальными id в React при кликах (React, JavaScript)

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

Компании: Kaspersky

Стек: React, JavaScript

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

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

Для добавления и удаления кнопок с уникальными id в React при кликах используйте состояние (useState) с массивом объектов, где каждый объект содержит id и другие данные. При клике на "добавить" генерируйте новый id (например, с помощью Date.now() или crypto.randomUUID()) и добавляйте элемент в массив. При клике на "удалить" фильтруйте массив по id. Обязательно используйте id как key при рендеринге списка.

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

Управление динамическим списком кнопок в React требует правильной работы с состоянием и ключами. Основная сложность - гарантировать уникальность id и эффективно обновлять UI при добавлении/удалении.

Генерация уникальных id: для простых случаев подходит Date.now(), но в production лучше использовать crypto.randomUUID() (современные браузеры) или библиотеку вроде uuid. Id не должны меняться между рендерами, иначе React будет пересоздавать DOM-элементы.

Работа с состоянием: используйте функциональную форму setState, чтобы избежать race conditions при быстрых кликах. При добавлении создавайте новый массив через spread-оператор, при удалении - через filter.

Ключи (keys): всегда используйте id как key для элементов списка. Это позволяет React эффективно обновлять только изменившиеся элементы, а не перерисовывать весь список.

Производительность: для больших списков (сотни+ элементов) рассмотрите виртуализацию (react-window). Для частых операций удаления/добавления используйте useMemo для стабильных ссылок на функции-обработчики.

На практике

В реальных проектах часто требуется не просто список кнопок, а управление их состоянием (активна/неактивна, текст, стили). Храните все данные в объекте внутри массива:

JAVASCRIPT
const [buttons, setButtons] = useState([]);
// Каждый элемент: { id: 'abc123', label: 'Кнопка 1', isActive: false }

При удалении важно передавать правильный id - обычно через замыкание в колбэке или data-атрибут. Избегайте использования индекса массива как id - это приводит к багам при удалении элементов из середины списка.

Для анимаций добавления/удаления используйте библиотеки вроде react-spring или framer-motion с AnimatePresence - они корректно работают с React-ключами.

Пример кода

JSX
import React, { useState, useCallback } from 'react';
const ButtonManager = () => {
const [buttons, setButtons] = useState([]);
const addButton = useCallback(() => {
const newButton = {
id: crypto.randomUUID(),
label: `Кнопка ${buttons.length + 1}`,
timestamp: Date.now()
};
setButtons(prev => [...prev, newButton]);
}, [buttons.length]);
const removeButton = useCallback((idToRemove) => {
setButtons(prev => prev.filter(btn => btn.id !== idToRemove));
}, []);
return (
<div>
<button onClick={addButton}>Добавить кнопку</button>
<div>
{buttons.map(btn => (
<button
key={btn.id}
onClick={() => removeButton(btn.id)}
style={{ margin: '4px' }}
>
{btn.label}
</button>
))}
</div>
</div>
);
};

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

Начните с ключевого принципа: состояние как единственный источник правды. Объясните, почему id должен быть уникальным и стабильным - это критично для React reconciliation. Упомяните, что используете функциональное обновление состояния для потокобезопасности.

Покажите понимание trade-off: crypto.randomUUID() vs Date.now() vs библиотеки. Для senior-уровня важно упомянуть edge cases: что если id закончатся (теоретически), как обрабатывать дубликаты, как тестировать такие компоненты.

Завершите практическим советом: всегда передавайте id через замыкание в обработчик, а не через data-атрибут, если не требуется доступ к DOM.

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

  • Понимание React-состояния и иммутабельности
  • Знание механизма ключей (keys) и reconciliation
  • Умение работать с асинхронностью setState
  • Способность предусмотреть edge cases (быстрые клики, удаление последнего элемента)
  • Понимание разницы между id и index как key
  • Знание современных API (crypto.randomUUID)

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

  • Использование индекса массива как key - приводит к багам при удалении/пересортировке
  • Мутация состояния напрямую (push вместо spread)
  • Генерация id внутри render без useMemo/useCallback - каждый рендер создаёт новый id
  • Отсутствие функциональной формы setState при быстрых кликах
  • Хранение id в состоянии, которое можно вычислить (derived state)
  • Использование Math.random() для id - не гарантирует уникальность в распределённых системах

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

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