我正在开发一个项目,使用 React Query 和 DnD Kit 来实现拖放功能。然而,当我将一个项目放到新位置时,它会短暂返回到其原始位置,然后再进入新位置。我还使用 DnD Kit 提供的 DragOverlay 功能,并遵循文档中规定的规则。
我目前正在使用 React Query 的 mutate 函数进行乐观更新,并且我尝试过使用 setQueryData 直接更新缓存,但我仍然看到这种闪烁。引入单独的本地状态来管理 DnD 更新可以阻止闪烁,但我更愿意避免为此目的添加额外的状态。
我的目标
我想实现流畅的拖放体验,而不需要重复状态。具体来说,我希望: 避免闪烁并防止项目暂时返回到其原始位置。 仅依靠 React Query 进行更新,而不引入新的本地状态。
我尝试过的:
乐观更新:使用 mutate 和 onMutate 来应用乐观更改。
直接缓存更新:删除后立即调用 setQueryData 以立即反映更改。
有人遇到过类似的问题或找到有效的方法来处理这种情况吗?
我正在使用:
"@dnd-kit/core": "^6.1.0",
"@dnd-kit/sortable": "^8.0.0",
"@dnd-kit/utilities": "^3.2.2",
"@tanstack/react-query": "^5.10.0",
我也遇到这个问题了!当我实现状态时,我可以让放置动画起作用,但它破坏了我的 React-Query 用例的整个目的。
这是我的相关代码:
const handleDragEnd = (e: DragEndEvent) => {
const taskId = e.active.id;
const priority = e.over?.id as string;
const task = tasks.find((t) => t.id === Number(taskId));
if (
task &&
priority &&
Object.values(Priority).includes(priority as Priority) &&
task.priority !== priority
) {
const newTask: TaskType = {
...task,
priority: priority as Priority,
};
updateTaskMutation.mutate(newTask);
}
};
const updateTaskMutation = useMutation({
mutationFn: updateTask,
onMutate: async (updatedTask) => {
queryClient.setQueryData<TaskType[]>(["tasks"], (oldData) =>
oldData?.map((task) => {
if (task.id === updatedTask.id) {
return updatedTask;
} else {
return task;
}
})
);
},
});
<TaskSection id={Priority.HIGH}>
{filteredTasks
.filter((task) => task.priority === "HIGH")
.map((task) => (
<Task task={task} key={task.id} />
))}
</TaskSection>
<TaskSection id={Priority.MEDIUM}>
{filteredTasks
.filter((task) => task.priority === "MEDIUM")
.map((task) => (
<Task task={task} key={task.id} />
))}
</TaskSection>
<TaskSection id={Priority.LOW}>
{filteredTasks
.filter((task) => task.priority === "LOW")
.map((task) => (
<Task task={task} key={task.id} />
))}
</TaskSection>
{/* it was very difficult to get the drop animation working with how react query handles state. It is one thing I would love to go back and figure out given more time */}
<DragOverlay>
{activeTask ? <Task task={activeTask} /> : null}
</DragOverlay>