에러 핸들링 with Tanstack Query #2

꾸준히·2025년 6월 24일

Tanstack Query

목록 보기
5/5

Tanstack Query의 에러 핸들링을 위해 블로그들을 찾아보면 useCallback을 사용하여 핸들러 훅을 만드는 것을 찾아볼 수 있음.

훅을 만들어서 사용하는 방법과 이전에 작성한 에러 핸들링 with Tanstack Query #1의 방식을 비교하고자 함.


일단,

  1. React 훅을 사용하려면 컴포넌트 함수나 커스텀 훅 내부에서만 사용할 수 있다
    index.tsx에서 사용 불가
  2. 그래서 훅을 이용한 핸들러를 적용하고 싶다면?
    App.tsx에서 사용해야한다

핸들러 훅(useCallback) 사용하기

// utils
export const useApiError = () => {
  const handleError = useCallback((error: unknown) => {
    // 에러 핸들링 with Tanstack Query #1 코드 참고
  }, []);

  return { handleError };
};
// App.tsx

function App() {

const { handleError } = useApiError();

const [queryClient] = useState(() => new QueryClient({
  queryCache: new QueryCache({
    onError: (error, query) => handleApiError(error),
   }),
   mutationCache: new MutationCache({
    onError: (error, _variables, _context, mutation) => handleApiError(error),
  }),
}));

return (
  <QueryClientProvider client={queryClient}>
  	{/* ... */}
  </QueryClientProvider>
  );
}

handleError를 왜 useCallback으로 썼는지

  1. 일단 컴포넌트 내부에서 부름 → 이 말은, 컴포넌트가 리렌더링 할 때마다 함수가 새로 만들어진다는 의미 이를 방지하기 위해 useCallback으로 만들어짐
  2. React Query 훅의 onError로 넘김
    참조 동일성 유지가 중요한데, useCallback으로 안하면 함수가 새로 만들어져서 React Query 내에서 불필요한 리패칭이나 리렌더링이 생길 수 있음

QueryClient에 useState 사용 이유

목적 : 컴포넌트 리렌더링 시 QueryClient 재생성되는거 방지하기 위해

  • new QueryClient도 객체임 → 렌더링시마다 새로운 인스턴스가 계속 생성됨 → 참조값이 다르니까 React는 새로운 값으로 인식해서 리렌더링함 → 같은 인스턴스를 계속 써야 캐시/쿼리 상태가 유지가 정상적으로 되는데, 새로운거를 만드니까
    문제 : 이전 캐시 날아감, 상태 리셋, 전역 에러 핸들링도 리셋, refetch도 꼬임 등
  • useState(() => ...)로 첫 렌더링 시 한 번만 실행되고 값 유지 → 객체 재생성 방지

✅ 전역 QueryClientProvider vs 컴포넌트 내부 QueryClientProvider 차이

  • 전역 QueryClientProvider에서는
    • index.tsx나 앱 최상단에 한 번만 QueryClient 인스턴스 생성하고, QueryClientProvider로 감쌈
    • 이 경우 queryClient 객체는 앱 라이프사이클 내내 한 번만 생성되고 재사용됨
    • 그래서 전역 onError 핸들러도 한 번만 등록되고 함수 참조가 계속 동일하니까 useCallback 필요없음
  • 컴포넌트 내부 QueryClientProvider에서는
    • App.tsx 같은 컴포넌트 내부에서 QueryClientProviderQueryClient를 생성하면
    • 컴포넌트가 리렌더링 될 때마다 새로운 인스턴스 생성하니까 훅을 useCallback으로 감쌌고,
    • queryClient도 객체니까 useState로 한 번만 생성하도록 해서 재사용

결론 : 전역은 앱 시작 시 1회 queryClient 생성하고, 컴포넌트 내부는 매 렌더 시마다 생성하니까 useCallback이나 useState가 필수

0개의 댓글