typescript - Tanstack React Query useMutation sempre verdadeiro em onSuccess
import { TNewServicesProps } from '@/_constants/types';
import api from '@/_libs/api';
import { useMutation, useQueryClient } from '@tanstack/react-query';
const useManageServices = (
method: 'create' | 'update' | 'delete',
item_id?: number | string,
values?: TNewServicesProps
) => {
if ((method === 'update' || method === 'delete') && item_id == null) {
throw new Error(`item_id is required for ${method} method`);
}
const queryClient = useQueryClient();
const { data, error, isPending, mutateAsync, isSuccess } = useMutation({
mutationKey: [`${method}_services`],
mutationFn: async () => {
switch (method) {
case 'create':
return await api
.post(
`/admin/services/`,
JSON.stringify(values !== undefined ? values : {})
)
.then((res) => res.data)
.catch((error) => error.response.data);
case 'update':
return await api
.patch(
`/admin/services/${item_id}/`,
JSON.stringify(values !== undefined ? values : {})
)
.then((res) => res.data)
.catch((error) => error.response.data);
case 'delete':
return await api
.delete(`/admin/services/${item_id}/`)
.then((res) => res.data)
.catch((error) => error.response.data);
default:
throw new Error(`Invalid method: ${method}`);
}
},
//this is always fired, even when response code is 400, 500, etc.
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: ['services'],
});
},
onError: () => {
//should do something but never fired
},
});
return { data, error, mutateStatus: mutateAsync, isPending, isSuccess };
};
export default useManageServices;
Atualmente, estou a experimentar o react-query no meu projeto.
Estou a enfrentar um problema com o tratamento de erros dentro da minha mutação.
Quando verifico o separador de rede, posso ver que o servidor responde com um código de estado 400 ou 500, o que presumi que faria com que o axios lançasse um erro, acionando a função onError definida.
No entanto, a função onSuccess é sempre invocada.
O que é que eu poderia estar a ignorar? Obrigado antecipadamente.
Resposta #1
Suspeito que o problema aqui é que a sua função de mutação está a interceptar os erros lançados antes que o hook useMutation possa tratá-los para realmente invocar qualquer manipulador onError fornecido.
Suspeito que você poderia ou não os apanhar de todo, ou simplesmente relançá-los depois de terem sido tratados.
const { data, error, isPending, mutateAsync, isSuccess } = useMutation({
mutationKey: [`${method}_services`],
mutationFn: async () => {
switch (method) {
case 'create':
return await api
.post(
"/admin/services/",
JSON.stringify(values !== undefined ? values : {})
)
.then((res) => res.data);
case 'update':
return await api
.patch(
`/admin/services/${item_id}/`,
JSON.stringify(values !== undefined ? values : {})
)
.then((res) => res.data);
case 'delete':
return await api
.delete(`/admin/services/${item_id}/`)
.then((res) => res.data);
default:
throw new Error(`Invalid method: ${method}`);
}
},
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: ['services'],
});
},
onError: () => {
// ...
},
});
const { data, error, isPending, mutateAsync, isSuccess } = useMutation({
mutationKey: [`${method}_services`],
mutationFn: async () => {
switch (method) {
case 'create':
return await api
.post(
"/admin/services/",
JSON.stringify(values !== undefined ? values : {})
)
.then((res) => res.data)
.catch((error) => {
// error.response.data
throw error;
});
case 'update':
return await api
.patch(
`/admin/services/${item_id}/`,
JSON.stringify(values !== undefined ? values : {})
)
.then((res) => res.data)
.catch((error) => {
// error.response.data
throw error;
});
case 'delete':
return await api
.delete(`/admin/services/${item_id}/`)
.then((res) => res.data)
.catch((error) => {
// error.response.data
throw error;
});
default:
throw new Error(`Invalid method: ${method}`);
}
},
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: ['services'],
});
},
onError: () => {
// ...
},
});
Resposta #2
Tal como a resposta do @Drew Reese mencionou, estás a capturar o erro prematuramente quando o react query já o está a fazer. Acho que uma versão simplificada do teu código pode tornar mais fácil ver o problema.
mutationFn: async () => {
const response = await api
.delete(`/admin/services/${item_id}/`)
.then((res) => { return res.data })
.catch((error) => {
// you're catching the error and returning the error response
return error.response.data
}
return response; // this will be error.response.data, mutationFn doesn't fail, thus call the onSuccess function.
}
