
React+TypeScript 를 사용한 프로젝트를 진행하면서 상태관리 도구로 React Query(Tanstack Query)를 사용하였습니다.
React와 TypeScript를 기반으로 프로젝트를 진행하며, 데이터 상태 관리를 위해 React Query(Tanstack Query) 를 사용했습니다. React Query는 상태 관리를 효율적으로 할 수 있는 라이브러리로, 데이터 가져오기, 캐싱, 동기화, 그리고 업데이트 처리를 간소화하는데에 최적화 되어 있습니다.
useQuery를 통해 데이터를 효율적으로 가져올 수 있습니다.
API 호출 코드가 간소화되며, 상태 및 라이프사이클 관리를 내장된 기능으로 처리합니다.
쿼리 키(Query Key)를 기반으로 데이터를 캐싱하여 불필요한 API 호출을 방지합니다.
내장된 isLoading, isError 플래그를 통해 로딩 상태 및 에러를 관리할 수 있습니다.
React Query를 사용하기 전, QueryClient를 설정해야 합니다. 아래는 프로젝트에서 사용한 queryClient.ts 파일의 예제입니다.
import { QueryClient } from 'react-query';
const queryClient = new QueryClient({
defaultOptions: {
queries: {
onError: (error: unknown) => {
const typedError = error as Error;
console.error('Global Error Handler:', typedError.message);
},
retry: 1, // 쿼리 실패 시 재시도 횟수
refetchOnWindowFocus: false, // 윈도우 포커스 시 재요청 방지
},
mutations: {
onError: (error: unknown) => {
const typedError = error as Error;
console.error('Mutation Error:', typedError.message);
},
},
},
});
export default queryClient;
React Query를 사용하려면 QueryClientProvider를 사용하여 QueryClient를 애플리케이션에 전달해야 합니다.
아래는 main.tsx 파일에서 QueryClientProvider를 적용한 예제입니다.
createRoot(document.getElementById('root')!).render(
<StrictMode>
<QueryClientProvider client={queryClient}>
<App />
</QueryClientProvider>
</StrictMode>,
);
React Query와 함께 사용하기 위해 API 요청 로직을 작성하였습니다. 이를 통해 서버에서 데이터를 가져오는 로직을 모듈화하였습니다.
const fetchData = async (path: string) => {
try {
const url = `${baseURL}${path}`;
const res = await fetch(url, { method: 'GET', headers: Headers });
if (!res.ok) {
throw new Error(`${res.status} Error!!`);
}
return await res.json();
} catch (error) {
throw error;
}
};
const fetchScore = async (id: number, country: string) => {
return fetchData(`/${id}/score/${country}`);
};
.
.
.
import { useQuery } from 'react-query';
const fetchData = async () => {
const response = await fetch('/api/data');
return response.json();
};
const ExampleComponent = () => {
const { data, isLoading, isError } = useQuery('exampleQuery', fetchData);
if (isLoading) return <div>Loading...</div>;
if (isError) return <div>Error!</div>;
return <div>{data}</div>;
};
프로젝트에서 데이터를 로드 시 재사용 가능한 커스텀 훅으로 추상화했습니다. 아래는 useQuery를 활용하여 작성된 커스텀 훅의 예시입니다.
import { useEffect, useState } from 'react';
import { UseQueryResult } from 'react-query';
import ErrorComponent from '@components/Common/ErrorComponent';
import LoadingComponent from '@components/Common/LoadingComponent';
export const useQuery = ({ query }: { query: UseQueryResult }) => {
const { data, isLoading, isError } = query;
const [isDeferred, setIsDeferred] = useState(false);
useEffect(() => {
const timeoutId = setTimeout(() => {
setIsDeferred(true);
}, 300);
return () => clearTimeout(timeoutId);
}, []);
if (isLoading) return [null, isDeferred && <LoadingComponent />];
if (isError) return [null, <ErrorComponent />];
return [data];
};
// query.ts
export const useIndexScoreQuery = () => {
return useQuery<IndexScoreInfo>(['indexScore'], () => fetchIndexScore(), queryOptions);
};
// IndexScore.tsx
const [indexScores, suspend] = useQueryComponent({ query: useIndexScoreQuery() });
React Query를 사용하여 데이터를 가져오는 코드와 상태를 간소화할 수 있었습니다.
- 기존의 복잡한 데이터 패칭 코드를 간결하게 작성 가능
- 현재 Query 상태를 활용한 간편한 로딩 및 에러처리
- 매우 직관적이고 간단하게 사용 가능