How to animate DnD? #409
-
I use simple template: <DndContext onDragEnd={handleDragEnd} >
<Droppable id="0">
{props.bins_map[0] !== 0 ? <Draggable id="0" /> : ""}
</Droppable>
<Droppable id="1">
{props.bins_map[1] !== 0 ? <Draggable id="1" /> : ""}
</Droppable>
<Droppable id="2">
{props.bins_map[2] !== 0 ? <Draggable id="2" /> : ""}
</Droppable>
</DndContext> Where bins_map stores 1 if there is a bin, 0 if there is not. But in the example animation very smooth.How to make this animation? |
Beta Was this translation helpful? Give feedback.
Replies: 3 comments 4 replies
-
In order for the drop animation to work, you need to actually move the draggable from one position in the tree to another. In this case, you aren't moving the draggable with |
Beta Was this translation helpful? Give feedback.
-
I have same question |
Beta Was this translation helpful? Give feedback.
-
Edit: In a previous version of this answer, I had forgotten to mention that I was using a DragOverlay, so I updated the answer accordingly. There's no need to actually move components in the DOM tree. If you use a DragOverlay, the animation will work fine as long as you assign the right IDs to your draggables. The following concept should work fine: const [items, setItems] = useState<Record<UniqueIdentifier, UniqueIdentifier[]>>({
containerA: ['item1', 'item3', 'item6'],
containerB: ['item5'],
containerC: ['item2', 'item4'],
});
const [activeDraggableId, setActiveDraggableId] = useState<UniqueIdentifier | null>(null);
const updateItems = (
oldItems: Record<UniqueIdentifier, UniqueIdentifier[]>,
activeId: UniqueIdentifier,
overId: UniqueIdentifier
) => {
if (oldItems[overId].includes(activeId)) {
return oldItems;
}
const newItems: Record<UniqueIdentifier, UniqueIdentifier[]> = {};
for (const container of Object.keys(oldItems)) {
newItems[container] = oldItems[container].filter((item) => item !== activeId);
if (container === overId) {
newItems[container] = [...newItems[container], activeId];
}
}
return newItems;
};
const onDragStart = useCallback(({ active }: DragStartEvent) => {
setActiveDraggableId(active.id);
}, []);
const onDragCancel = useCallback(() => {
setActiveDraggableId(null);
}, []);
const onDragEnd = useCallback(({ active, over }: DragEndEvent) => {
setActiveDraggableId(null);
if (!over || !active) {
return;
}
setItems((i) => updateItems(i, active.id, over.id));
}, []);
<DnDContext onDragStart={onDragStart} onDragCancel={onDragCancel} onDragEnd={onDragEnd}>
{Object.keys(items).map((containerId) => (
<Droppable id={containerId} subItems={items[containerId]} />
))}
{createPortal(
<DragOverlay>
{!!activeDraggableId && <Item text={activeDraggableId} />}
</DragOverlay>,
document.body
)}
</DnDContext> and within Droppable: interface Props {
id: UniqueIdentifier;
subItems: UniqueIdentifier[];
}
const Droppable = ({id, subItems}: Props) => {
const { setNodeRef } = useDroppable({ id: id});
return (
<div ref={setNodeRef}>
{subItems.map((subItem) => (
<Draggable id={subItem} key={subItem}>
<Item text={subItem} />
</Draggable>
))}
</div>
);
} The Draggable components are mapped with IDs from a UniqueIdentifier array. As long as the Record that holds those IDs is updated correctly, the Draggable components will have correct animations that move them to their new container. |
Beta Was this translation helpful? Give feedback.
In order for the drop animation to work, you need to actually move the draggable from one position in the tree to another.
In this case, you aren't moving the draggable with
id="0"
to be inside the droppable withid="1"
, you are just un-mounting the draggable withid="0"
and mounting a new draggable withid="1"
within the droppable ofid="1"
, which i why the drop animation is not working.