React Query 좀 더 우아하게 사용해보기
React Query로 커스텀 훅, 전역 로딩, 에러 핸들링 사용 해보기
react-query
를 어떻게 더 깔끔하고 실무적으로 사용할 수 있는지
1. 커스텀 훅으로 feature 별로 분리하기
- 커스텀 훅으로 feature별로 관리하면 관리하기도 좋고 유지 보수에 좋다.
export function useStaff() {
const [filter, setFilter] = useState("all");
const fallback: Staff[] = [];
const { data: staff = fallback } = useQuery({
queryKey: [queryKeys.staff],
queryFn: getStaff,
});
return { staff, filter, setFilter };
}
export function useTreatments(): Treatment[] {
const fallback: Treatment[] = [];
const { data = fallback } = useQuery({
queryKey: [queryKeys.treatments],
queryFn: getTreatments,
});
return data;
}
위 코드와 같이 커스텀 훅을 사용하면 feature 별로 API에서 요청 받은 데이터를 독립적으로 컴포넌트 내에서 사용 할 수 있다
2. 쿼리 키 상수로 관리하기
쿼리를 사용할 때 마다 쿼리키를 직접 타이핑해서 사용하는 것 보다 상수로 관리 하는게 유지보수 측면에서 당연히 좋다.
export const queryKeys = {
treatments: "treatments",
appointments: "appointments",
staff: "staff",
user: "user",
};
Query Key를 상수로 관리하면 오타를 줄이고 재사용성과 유지보수성을 높일 수 있다.
3. useIsFetching 으로 전역 로딩 상태를 다뤄보자
먼저 useIsFetching은 현재 앱 내부에서 실행 중인 모든 쿼리 개수를 반환한다. 숫자가 0이면 현재 아무것도 fetching 중인 상태가 아니고 1이상이면 1개 이상의 데이터를 서버에 요청하는 훅이다.
function Loading() {
const isFetching = useIsFetching();
if (!isFetching) return null;
return <Spinner />;
}
QueryClientProvider 안에 전역으로 사용할 로딩 컴포넌트를 배치하고 useIsFetching으로 로딩 상태 관리를 쉽게 할 수 있다.
// App.tsx 내부
<QueryClientProvider client={queryClient}>
<AuthContextProvider>
<Loading />
<BrowserRouter>{/* 라우트 컴포넌트들 */}</BrowserRouter>
</AuthContextProvider>
</QueryClientProvider>
전역 로딩 인디케이터를 한 번에 처리할 수 있어 사용자 경험을 향상시킬 수 있습니다.
4. 전역으로 성공/에러/로딩 처리하기 (QueryCache)
- useQuery로 요청한 쿼리 결과와 상태 등을 캐싱한다.
- 그리고 설정한 쿼리에 대해 성공,에러,로딩 상태를 추적해준다
먼저 에러 처리에 대해 예시를 들자면 아래 코드와 같이 공통으로 처리할 에러를 onError
로 처리해 토스트를 사용할 수 있다.
function errorHandler(errorMsg: string) {
const id = "react-query-toast";
if (!toast.isActive(id)) {
toast({
id,
title: `데이터를 불러올 수 없습니다: ${errorMsg}`,
status: "error",
variant: "subtle",
isClosable: true,
});
}
}
export const queryClient = new QueryClient({
queryCache: new QueryCache({
onError: (error) => {
errorHandler(error.message);
},
}),
});
const id = "react-query-toast";는 에러가 발생했을때 토스트가 중복처리 되는 걸 막기 위함이다.
5. react-query-devtools로 디버깅 해주면 개발 할 때 query 상태를 추적할 수 있다.
import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
<ReactQueryDevtools initialIsOpen={false} />;