T
TanStack•3y ago
xenial-black

setQueryData old data type

I'm not sure if I'm doing this correctly - but old will always be defined - or will it? Should I have to account for old being undefined as per the type error? In what case would this be undefined?
No description
5 Replies
xenial-black
xenial-blackOP•3y ago
export const useRestrictUser = (id: string) => {
const queryClient = useQueryClient();

return useMutation({
mutationFn: () => userClient.restrictUser(id),
onSuccess: () => {
queryClient.setQueryData(['users', 'view', id], (old: UserData): UserData => ({ ...old, status: 'restricted' }));
},
});
};
export const useRestrictUser = (id: string) => {
const queryClient = useQueryClient();

return useMutation({
mutationFn: () => userClient.restrictUser(id),
onSuccess: () => {
queryClient.setQueryData(['users', 'view', id], (old: UserData): UserData => ({ ...old, status: 'restricted' }));
},
});
};
Hmm and if I add the type to setQueryData it's complaining that the type of uuid isn't compatible - it's somehow making everything optional?
xenial-black
xenial-blackOP•3y ago
No description
xenial-black
xenial-blackOP•3y ago
const restrictUser = (id: string) => {
const queryClient = useQueryClient();

const key = ['users', 'view', id];

return useMutation({
mutationFn: () => userClient.restrictUser(id),
onMutate: async () => {
await queryClient.cancelQueries(key);

const previousUser = queryClient.getQueryData<UserData>(key);

if (previousUser) {
queryClient.setQueryData<UserData>(key, { ...previousUser, status: 'restricted' });
}

return { previousUser };
},
onError: (err, variables, context) => {
if (context?.previousUser) {
queryClient.setQueryData<UserData>(key, context.previousUser);
}
},
});
};
const restrictUser = (id: string) => {
const queryClient = useQueryClient();

const key = ['users', 'view', id];

return useMutation({
mutationFn: () => userClient.restrictUser(id),
onMutate: async () => {
await queryClient.cancelQueries(key);

const previousUser = queryClient.getQueryData<UserData>(key);

if (previousUser) {
queryClient.setQueryData<UserData>(key, { ...previousUser, status: 'restricted' });
}

return { previousUser };
},
onError: (err, variables, context) => {
if (context?.previousUser) {
queryClient.setQueryData<UserData>(key, context.previousUser);
}
},
});
};
genetic-orange
genetic-orange•3y ago
From typescript perspective we have no way of knowing if ['users', 'view', id] was already fetched, was never fetched or maybe it's just fetching in the background. Even if in your codebase, there is no way of using the mutation without fetching this query, it's not always guaranteed. Therefore it is always good to check if old data exists and handle the non-existing state. This could prevent bugs in the future when someone could use the mutation with arbitrary id without prefetching said query first.
xenial-black
xenial-blackOP•3y ago
Looks like this is the way to go Thanks 🙂 Yeah I consulted the docs and blog about this and did it as above Still trying to work out the best patterns in Vue Just realised today you can do onError in the component as well
await updateUserMutation.mutateAsync(data, {
onError: (error: AxiosError | unknown) => {
if (error instanceof AxiosError) {
mapErrors(error);
}
},
});
await updateUserMutation.mutateAsync(data, {
onError: (error: AxiosError | unknown) => {
if (error instanceof AxiosError) {
mapErrors(error);
}
},
});
Not sure if I'm doing the typecheck properly there But this is to map errors to a form But also in the global mutation it rolls back some optimistic updates Sure is nice

Did you find this page helpful?