This is my sortable list compon
const [active, setActive] = useState<Active | null>(null);
const activeItem = useMemo(
() => items.find((item) => item.id === active?.id),
[active, items],
);
return (
<DndContext
modifiers={[restrictToVerticalAxis, restrictToParentElement]}
sensors={sensors}
onDragStart={({ active }) => {
setActive(active);
}}
onDragEnd={({ active, over }) => {
if (over && active.id !== over?.id) {
const activeIndex = items.findIndex(({ id }) => id === active.id);
const overIndex = items.findIndex(({ id }) => id === over.id);
onChange(arrayMove(items, activeIndex, overIndex));
}
setActive(null);
}}
onDragCancel={() => {
setActive(null);
}}
>
<SortableContext
items={itemsWithIds}
strategy={verticalListSortingStrategy}
>
<ul
role="application"
className={cn('flex list-none flex-col p-0', gap)}
>
{items.map((item, index) => (
<React.Fragment key={item.id}>
{renderItem(item, index)}
</React.Fragment>
))}
</ul>
</SortableContext>
<SortableOverlay>
{activeItem ? renderItem(activeItem) : null}
</SortableOverlay>
</DndContext>
);
When I use the sortable overlay (which is a wrapper for DragOverlay
), I noticed my component that is rendered flashes, it has some fetch logic in the item, its using react query so it uses the cached data, but it sets it to null for just a second as the item is rendered.
This doesn’t happen when I don’t use DragOverlay
as it isn’t creating a copy.
I have a couple ideas of how to solve this but I’m not sure how to do it.
One would be to somehow render the component with its state in one place, and copy it completely with its state, so it doesn’t have to call the hook again to get the data.
Is this something that is possible?
If that’s not possible, is there a way to have drop animations without DragOverlay
?
One other idea I had, would it possible to have the item that is dragging not be the newly created one, for example when you drag the item without DragOverlay
it doesn’t flash, it only flashes when a new item is created to be dragged, and the the old item is transparent underneath to show where the item will end up.
If it’s possible to swap these two around so that the dragging item is the original component, and the copy is underneath transparent, then the flash wont be a problem.
I’m sure some people will suggest moving the state up, which I’m not sure will be effective using our code base as we use multiple simple API endpoints/hooks, so in these components there will be multiple hooks to get the data, and use caching to make sure performance is ok.