Любопытный случай перетаскивания
Перетаскивание может выглядеть как простое взаимодействие с пользователем, при котором вы берете элемент и помещаете его в другое место, аналогично организации элементов на доске Trello или в любом интерфейсе в стиле Kanban, где карточки или информацию можно легко переставлять с помощью щелчка и перетаскивания.
Однако весь этот процесс скрывает за собой много сложностей. Начнем с перемещения данных между разными частями и получения правильной позиции размещения. Эта проблема усложняется, когда у вас есть вложенный слой элементов, которые могут перемещаться по нескольким уровням.
Чтобы реализовать это, нам не придется изобретать велосипед, в нашем распоряжении есть несколько библиотек. Наиболее популярные из них:
- response-beautiful-dnd выделяется как наиболее часто используемый, он предоставляет чистый и высокоуровневый API с большим количеством абстракции. Он был разработан Atlassian.
- React-DND довольно мощный, но немного сложный и требует некоторого привыкания.
- dnd-kit — один из новейших, современный, легкий и производительный.
Проблема
Мы в epilot широко полагались на React-beautiful-dnd
и в различных частях нашего приложения.
Тем не менее, в определенных контекстах мы столкнулись с некоторыми препятствиями при попытке реализовать некоторые сложные сценарии, в которых не удалось точно предсказать место падения элемента. Вот один из примеров.
Мы разработали несколько хаков для конкретных крайних случаев, но они не смогли решить все проблемы. Из-за этих крайних случаев код для перемещения данных элемента на основе позиции перетаскивания превратился в код спагетти. Прекращение обслуживания и поддержки response-beautiful-dnd
также не способствовало продолжению его использования.
Решение
Наконец, мы решили изучить альтернативные библиотеки, которые могли бы решить наши проблемы с помощью более явного, интуитивно понятного и простого API. Оценив несколько вариантов, мы остановились на dnd-kit
, поскольку он предоставляет явный и простой API. Дополнительным преимуществом было то, что он также предоставляет API-интерфейс перехватчиков, который отсутствует в некоторых старых библиотеках.
Ключевые преимущества dnd-kit
включают в себя:
- Нулевые зависимости
- Оптимизированная производительность
- Доступность
- Поддержка нескольких методов ввода
- Полная документация и примеры
Покажи мне код
Вот коды для простого перетаскивания обеих библиотек.
// react-beautiful-dnd
export const DragDrop = ({ initialData }) => {
const [items, setItems] = useState(initialData);
const onDragEnd = () => { /** moving data **/ };
return (
<DragDropContext onDragEnd={onDragEnd}>
<Droppable droppableId="droppable">
{(provided) => (
<ul {...provided.droppableProps} ref={provided.innerRef}>
{items.map((item, index) => (
<DraggableItem item={item} key={item.id} index={index} />
))}
{provided.placeholder}
</ul>
)}
</Droppable>
</DragDropContext>
);
};
const DraggableItem = ({ item, index }) => (
<Draggable draggableId={item.id} index={index}>
{(provided) => (
<li
{...provided.draggableProps}
{...provided.dragHandleProps}
ref={provided.innerRef}
>
{item.content}
</li>
)}
</Draggable>
);
// dnd-kit
export const DndKit = ({ initialData }) => {
const [items, setItems] = useState(initialData);
const onDragEnd = () => { /** moving data **/ };
const sensors = useSensors(useSensor(PointerSensor));
return (
<DndContext
sensors={sensors}
collisionDetection={closestCenter}
onDragEnd={handleDragEnd}
>
<SortableContext items={items} strategy={verticalListSortingStrategy}>
<ul>
{items.map((item) => (
<DraggableItem item={item} key={item.id} />
))}
</ul>
</SortableContext>
</DndContext>
);
};
const DraggableItem = ({ item }) => {
const {
attributes,
isDragging,
listeners,
setNodeRef,
transform,
transition,
} = useSortable({
id: item.id,
});
const style = {
transform: CSS.Transform.toString(transform),
transition,
cursor: isDragging ? "grabbing" : "grab",
};
return (
<li
{...attributes}
{...listeners}
key={item.id}
data-dnd-id={item.id}
data-dnd-type="item"
ref={setNodeRef}
style={style}
>
{item.content}
</li>
);
};
Полный код можно найти в этой Codesandbox.
Среди этих примеров кода, имеющих одинаковую функциональность, можно заметить, что dnd-kit
имеет более высокую сложность, но также и более комплексный. Для решения этой проблемы он использует Sortable, поскольку это один из вариантов использования, который он решает. Это соответствует нашей цели — решать более сложные сценарии с помощью вложенного перетаскивания и возможности перетаскивания между разными уровнями.
Ключевые преимущества dnd-kit
, которые пригодились, включают в себя:
- Пользовательский заполнитель. Это один из наиболее желательных вариантов использования. Достичь этого в
React-beautiful-dnd
может быть непросто, так как у него будут ограниченные возможности и много JavaScript для достижения удовлетворительного состояния. В нашем сценарии мы хотели показать сжатую версию элемента с дочерними элементами во время перетаскивания, поэтому мы использовалиDragOverlay
с порталом React.
- Стратегии обнаружения столкновений. Предлагает различные стратегии, специфичные для разных вариантов использования, обеспечивая контроль над переключением элементов внутри дерева. Вы даже можете разработать свою собственную стратегию, отвечающую вашим требованиям.
- Стратегии сортировки. Аналогично, он предлагает различные стратегии сортировки, позволяющие сортировать вертикальные списки, горизонтальные списки или сетки.
Ознакомьтесь с этой упрощенной версией нашего варианта использования на Epilot с функцией перетаскивания вложенных элементов в этой песочнице Codes.
Заключение
В конечном счете, выбор между ними зависит от ваших конкретных требований, предпочтений и желаемого уровня настройки. Если вы предпочитаете более простой и самоуверенный подход, лучшим выбором будет action-beautiful-dnd. Если вам нужны дополнительные возможности настройки и контроля, dnd-kit
может лучше соответствовать вашим потребностям.