blog
TanStack Query와 axios 에러 처리 메모
Front-end / React#TanStack Query#React Query#axios#에러 처리#팁 모음
mutate vs mutateAsync
mutate: 반환값이 없다(void). 결과는onSuccess·onError콜백으로 처리한다. 에러가 나도 throw하지 않는다.mutateAsync: Promise를 반환한다. 응답을await로 바로 받아 이어서 처리할 때 쓴다.
const { mutateAsync } = useMutation({ mutationFn: createPost });
const handleSubmit = async () => {
try {
const post = await mutateAsync(form);
router.push(`/posts/${post.id}`);
} catch {
// mutateAsync는 실패 시 reject하므로 직접 처리해야 함
}
};
mutateAsync의 에러를 잡지 않으면 처리되지 않은 Promise rejection이 된다. 대부분의 경우 mutate + 콜백으로 충분하다.
onSuccess 안에서 throw하면
mutationFn이 성공해도 onSuccess 콜백 안에서 에러를 던지면, 그 mutation은 실패로 처리되어 onError가 호출된다. HTTP 200이지만 본문의 code로 실패를 판단하는 API라면, mutationFn 안에서 검사해 던지는 편이 흐름이 명확하다.
mutationFn: async (body) => {
const { data } = await api.post('/orders', body);
if (data.code !== 0) throw new Error(data.message);
return data.data;
},
onError는 언제 호출되나
mutationFn(또는 queryFn)이 반환한 Promise가 reject되면 호출된다.
- axios는 기본적으로 2xx가 아닌 응답에서
AxiosError를 throw한다. - API 함수에서
Promise.reject(...)를 반환하거나throw해도 마찬가지다. - 반대로 HTTP 200에 본문으로 실패를 알리는 API는 직접 throw하지 않는 한 성공으로 처리된다.
axios 에러는 try/catch로 받는다
try {
await api.get('/me');
} catch (error) {
if (axios.isAxiosError(error)) {
console.log(error.response?.status, error.response?.data);
}
}
axios는 요청이 실패하면 내부에서 AxiosError를 throw하고, 가장 가까운 catch가 받는다. TypeScript에서 catch의 error는 unknown이므로 axios.isAxiosError로 좁혀서 쓴다.
enabled
enabled: false인 쿼리는 자동으로 실행되지 않는다.
refetch()를 직접 호출하면enabled와 관계없이 실행된다.enabled가false에서true로 바뀌면, 캐시에 데이터가 없거나 stale인 경우 자동으로 요청한다. 따로refetch()를 부를 필요가 없다.
사용자 입력이 생길 때까지 요청을 미루는 경우 enabled: !!keyword처럼 조건을 걸어 두면 된다.
const { data } = useQuery({
queryKey: ['search', keyword],
queryFn: () => search(keyword),
enabled: keyword.length > 0,
});