useDroppableCollection для коллекций

useDroppableCollection — это хук из библиотеки React Aria, предназначенный для управления интерактивными коллекциями элементов, которые могут быть целями перетаскивания (drop targets) в интерфейсах с поддержкой drag-and-drop. Он предоставляет набор свойств и методов, упрощающих создание доступных и предсказуемых коллекций, совместимых с современными стандартами доступности (ARIA).


Основные возможности

  1. Определение области приёма элементов useDroppableCollection позволяет явно указать контейнер, который будет принимать перетаскиваемые элементы. Это важно для коллекций, где каждая ячейка может быть отдельной целью, либо вся коллекция целиком.

  2. Автоматическая поддержка ARIA Хук автоматически генерирует атрибуты, необходимые для доступности: aria-dropeffect, aria-label, а также события, обеспечивающие корректное взаимодействие с экранными считывателями.

  3. События drag-over и drag-leave Хук управляет внутренними состояниями при наведении элемента на коллекцию и его покидании. Это позволяет визуально выделять активные зоны и давать обратную связь пользователю.

  4. Интеграция с useDraggableItem Коллекции, созданные через useDroppableCollection, легко комбинируются с перетаскиваемыми элементами, реализуемыми через useDraggableItem, что упрощает построение сложных интерактивных интерфейсов.


Сигнатура хука

const { collectionProps, dragState } = useDroppableCollection(options);

Параметры options

  • collectionRef — ссылка на DOM-элемент контейнера коллекции.
  • disabled — логическое значение, указывающее, активна ли зона приема.
  • onDrop — функция обратного вызова, вызываемая при успешной операции drop.
  • onDragEnter — функция, срабатывающая при наведении draggable элемента на коллекцию.
  • onDragLeave — функция, срабатывающая при уходе draggable элемента с коллекции.
  • onDragOver — позволяет настраивать поведение при нахождении draggable элемента над зоной.

Возвращаемые значения

  • collectionProps — объект свойств, который нужно передать контейнеру коллекции. Содержит aria-атрибуты, обработчики событий и другие вспомогательные свойства.

  • dragState — объект, содержащий текущие состояния перетаскивания:

    • isOver — указывает, находится ли перетаскиваемый элемент над коллекцией.
    • isDragging — отражает процесс перемещения элемента.
    • dropEffect — текущее действие, которое будет выполнено при отпускании элемента (copy, move, none).

Пример использования

import { useDroppableCollection } from '@react-aria/dnd';
import { useRef } from 'react';

function DroppableList({ items, onDrop }) {
  const collectionRef = useRef(null);

  const { collectionProps, dragState } = useDroppableCollection({
    collectionRef,
    onDrop,
  });

  return (
    <ul {...collectionProps} ref={collectionRef}>
      {items.map(item => (
        <li key={item.id}>{item.name}</li>
      ))}
      {dragState.isOver && <div className="highlight-zone" />}
    </ul>
  );
}

В этом примере:

  • collectionProps автоматически назначает все необходимые ARIA-атрибуты и обработчики drag-and-drop.
  • dragState.isOver позволяет визуально подсветить область, когда перетаскиваемый элемент находится над списком.
  • Использование ref обеспечивает корректное отслеживание DOM-элемента коллекции.

Работа с вложенными коллекциями

useDroppableCollection поддерживает вложенные коллекции. Для этого каждый дочерний контейнер может использовать отдельный вызов хука, либо один хук может управлять всей иерархией через структуру данных коллекции. Основные правила:

  1. Для каждой вложенной зоны создается отдельный collectionRef.
  2. onDrop можно назначить на уровне вложенного контейнера или всей коллекции, в зависимости от логики.
  3. ARIA-атрибуты корректно наследуются и передаются вниз по дереву элементов.

Оптимизация производительности

При работе с большими коллекциями рекомендуется:

  • Использовать React.memo для элементов списка, чтобы предотвратить лишние перерендеры.
  • Ограничить количество событий onDragOver, чтобы не перегружать рендеринг.
  • Применять виртуализацию для длинных списков вместе с useDroppableCollection.

Советы по визуальной обратной связи

  • Для выделения активной зоны часто используют dragState.isOver, создавая подсветку или анимацию.
  • Можно комбинировать с CSS-перетаскиванием (transition, box-shadow) для плавного UX.
  • Вложенные коллекции могут использовать разный стиль выделения для родителя и дочернего элемента, чтобы не создавать путаницы.

Совместимость с TypeScript

Типизация хука выглядит так:

interface DroppableCollectionOptions {
  collectionRef: React.RefObject<HTMLElement>;
  disabled?: boolean;
  onDrop?: (event: DragEvent) => void;
  onDragEnter?: (event: DragEvent) => void;
  onDragLeave?: (event: DragEvent) => void;
  onDragOver?: (event: DragEvent) => void;
}

interface DroppableCollectionResult {
  collectionProps: React.HTMLAttributes<HTMLElement>;
  dragState: {
    isOver: boolean;
    isDragging: boolean;
    dropEffect: 'none' | 'copy' | 'move';
  };
}

Типизация гарантирует безопасное использование хука в больших проектах и упрощает интеграцию с IDE, автоматически подсказывая доступные события и состояния.


Если нужно, могу подготовить расширенный пример с множественными вложенными коллекциями и динамическим drag-and-drop, с полноценной визуализацией зон при наведении и поддержкой keyboard navigation.