T
TanStack•4y ago
genetic-orange

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
genetic-orange
genetic-orangeOP•4y 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?
genetic-orange
genetic-orangeOP•4y ago
No description
genetic-orange
genetic-orangeOP•4y 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);
}
},
});
};
fair-rose
fair-rose•4y 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.
genetic-orange
genetic-orangeOP•4y 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?