T
TanStack2y ago
mute-gold

Mutation optimistic updated slows down the UI

I have an app in which a user can upload files and then interact with them - add to favorite, change display name, etc.. One of the functionalities is to delete a file. I use tanstack mutation to do optimistic updates for the files deletion - all the files are inside a table.
const mutation = useMutation({
mutationFn: fileService.deleteFile,
mutationKey: ["delete", id],
onSettled: async () => {
queryClient.invalidateQueries({
queryKey: filesKeys.getFilesKey(),
});
},
onMutate: async () => {
const previousFiles = queryClient.getQueryData<File[]>(filesKeys.getFilesKey());

const newFiles = previousFiles?.filter((file) => file.fileId.toString() !== id);
queryClient.setQueryData(filesKeys.getFilesKey(), newFiles ?? []);

return { previousFiles };
},
onError: (_error, _variables, context) => {
if (context) {
queryClient.setQueryData(filesKeys.getFilesKey(), context.previousFiles);
}

message.error({
content: "Error deleting file",
key: "delete-file",
});
},
});
const mutation = useMutation({
mutationFn: fileService.deleteFile,
mutationKey: ["delete", id],
onSettled: async () => {
queryClient.invalidateQueries({
queryKey: filesKeys.getFilesKey(),
});
},
onMutate: async () => {
const previousFiles = queryClient.getQueryData<File[]>(filesKeys.getFilesKey());

const newFiles = previousFiles?.filter((file) => file.fileId.toString() !== id);
queryClient.setQueryData(filesKeys.getFilesKey(), newFiles ?? []);

return { previousFiles };
},
onError: (_error, _variables, context) => {
if (context) {
queryClient.setQueryData(filesKeys.getFilesKey(), context.previousFiles);
}

message.error({
content: "Error deleting file",
key: "delete-file",
});
},
});
There is nothing special in this specific example. When a user click the button the onMutate function fires and it filters the files to remove the file id. The problem it that is slows down the UI, not by a lot of course but in some sense. I've added a video for reference - in this video I have around 200 files that it filter. I'd appreciate any answer and if it is a problem at all.
2 Replies
rival-black
rival-black2y ago
My guess is that tanstack isn't to blame here. Either invalidating the queryKey causes too much work (too many http reqs etc.) or your UI code is re-rendering all 200 files when it shouldn't be. Without the UI code or useQuery(<fileKey>,...) it's impossible to tell anymore
mute-gold
mute-goldOP2y ago
export const useGetFiles = () => {
const { message } = App.useApp();
const { user } = useAuthContext();
if (!user) {
throw new Error("User not found");
}

const query = useGetUserFiles();
const { isError, error } = query;

useEffect(() => {
if (isError && error) {
message.error({
content: error.message,
key: "get-user-files",
});
}
}, [error, isError, message]);

return { query };
};
export const useGetFiles = () => {
const { message } = App.useApp();
const { user } = useAuthContext();
if (!user) {
throw new Error("User not found");
}

const query = useGetUserFiles();
const { isError, error } = query;

useEffect(() => {
if (isError && error) {
message.error({
content: error.message,
key: "get-user-files",
});
}
}, [error, isError, message]);

return { query };
};
This the the useQuery
export const useGetUserFiles = () => {
return useQuery({
queryKey: filesKeys.getFilesKey(),
queryFn: fileService.getFiles,
});
};
export const useGetUserFiles = () => {
return useQuery({
queryKey: filesKeys.getFilesKey(),
queryFn: fileService.getFiles,
});
};

Did you find this page helpful?