React Query with DnD Kit: Item Goes Back to Original Position for a Split Second on Drop Despite Optimistic Updates #1522
Replies: 4 comments 1 reply
-
This is not answering your question, but just wanted to share that I have the exact same problem, and I ended up eliminating the flicker with an extra bit of local state – like you did. I don't worry too much about it, since dnd-kit fires off a million re-renders while dragging anyway, so the extra state is not going to make a difference (in my case). Of course, if your dataset is huge, it might be different. Just my two cents... |
Beta Was this translation helpful? Give feedback.
-
The same issue! Here is a live example: https://codesandbox.io/p/devbox/romantic-spence-ytc286?workspaceId=ws_D6cM9BcQkbTvXKWa7jXzF2 |
Beta Was this translation helpful? Give feedback.
-
I also had similar difficulties using Dnd with React Query. I suggest to add the swap logic and update the cache with setQueryData(newArrayOrder) both in onDragEnd and onDragOver functions https://codesandbox.io/p/sandbox/priceless-silence-c26q2q Make sure to clone objects in the array if the data is more complex than simple types because it can also cause problems |
Beta Was this translation helpful? Give feedback.
-
have had this issue, here's what i've been through:
landed on this reliable solution to work around this race condition (hint: still uses local state, but without any need for useEffect syncing). here's a hook that encapsulates the mutation and local state usage. type EntryBase = { id: string; order: number };
export const useDragReorder = <Entry extends EntryBase>(entries: Entry[]) => {
const client = useQueryClient();
const [tempEntries, setTempEntries] = useState<Entry[] | null>(null);
const update = useMutation({
mutationFn: (_updates: EntryBase[]) => Promise.resolve(), // do your thing
onMutate: updates => {
// still perform optimistic update in react query
client.setQueryData<Entry[]>(['your', 'query', 'key'], prev => {
if (!prev) {
return [];
}
const next = prev.map(entry => {
const update = updates.find(u => u.id === entry.id);
if (update) {
return { ...entry, order: update.order };
}
return entry;
});
sortByOrder(next);
return next;
});
},
});
const reorder = useCallback(
async (event: DragEndEvent) => {
// your logic for determining:
// a) any updates to send to backend
// b) the new optimistic order of the items
const outcome = handleEntryDragReorder(event, entries);
if (!outcome) {
return;
}
setTempEntries(outcome.reordered);
await update.mutateAsync(outcome.updates);
setTempEntries(null);
},
[update, entries]
);
return {
reorder,
// critical - pass this to dnd kit sortable for order and item rendering
dragItems: tempEntries ?? entries,
};
}; |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
I'm working on a project using React Query with DnD Kit to implement drag-and-drop functionality. However, when I drop an item in a new position, it briefly returns to its original position for a split second before settling into the new position. I’m also using the dragOverlay feature provided by DnD Kit and have followed the rules stated in the documentation.
I’m currently using optimistic updates with React Query’s mutate function, and I’ve tried directly updating the cache with setQueryData, but I still see this flicker. Introducing a separate local state to manage the DnD updates stops the flickering, but I'd prefer to avoid adding additional state just for this purpose.
My Goal
I want to achieve a smooth drag-and-drop experience without duplicating state. Specifically, I'm looking to: Avoid the flicker and prevent the item from momentarily returning to its original position. Rely solely on React Query for the updates, without introducing a new local state.
What I've Tried:
Optimistic updates: Using mutate with onMutate to apply optimistic changes.
Direct cache update: Calling setQueryData immediately upon drop to reflect the change instantly.
Has anyone faced a similar issue or found an effective way to handle this scenario?
I am using:
"@dnd-kit/core": "^6.1.0",
"@dnd-kit/sortable": "^8.0.0",
"@dnd-kit/utilities": "^3.2.2",
"@tanstack/react-query": "^5.10.0",
Beta Was this translation helpful? Give feedback.
All reactions