React Query(Tanstack Query) 사용하기

뚜루미·2025년 1월 15일

React

목록 보기
34/39
post-thumbnail

React+TypeScript 를 사용한 프로젝트를 진행하면서 상태관리 도구로 React Query(Tanstack Query)를 사용하였습니다.

React Query를 활용한 상태 관리 및 커스텀 훅 활용

React와 TypeScript를 기반으로 프로젝트를 진행하며, 데이터 상태 관리를 위해 React Query(Tanstack Query) 를 사용했습니다. React Query는 상태 관리를 효율적으로 할 수 있는 라이브러리로, 데이터 가져오기, 캐싱, 동기화, 그리고 업데이트 처리를 간소화하는데에 최적화 되어 있습니다.

React Query 공식문서

React Query의 장점

1. 데이터 가져오기 간편화

useQuery를 통해 데이터를 효율적으로 가져올 수 있습니다.
API 호출 코드가 간소화되며, 상태 및 라이프사이클 관리를 내장된 기능으로 처리합니다.

2. 자동 데이터 캐싱

쿼리 키(Query Key)를 기반으로 데이터를 캐싱하여 불필요한 API 호출을 방지합니다.

3. 로딩 및 에러 관리

내장된 isLoading, isError 플래그를 통해 로딩 상태 및 에러를 관리할 수 있습니다.

React Query의 기본 설정

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>,
);

API 요청 로직 구현

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}`);
};
.
.
.

React Query에서의 useQuery의 기본적인 활용 방법

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를 사용하여 데이터를 가져오는 코드와 상태를 간소화할 수 있었습니다.

React Query와 함께한 프로젝트의 이점

  1. 기존의 복잡한 데이터 패칭 코드를 간결하게 작성 가능
  2. 현재 Query 상태를 활용한 간편한 로딩 및 에러처리
  3. 매우 직관적이고 간단하게 사용 가능

0개의 댓글