React Library – Tanstack Query


FrontEnd 개발에서 데이터 fetching과 상태 관리는 필수적인 작업입니다. 특히, 서버와의 통신이 빈번한 애플리케이션에서는 데이터의 캐싱, 동기화, 에러 처리와 같은 작업이 복잡해질 수 있습니다. 이런 문제를 해결하기 위해 등장한 라이브러리가 바로 TanStack Query입니다. 이 포스트에서는 TanStack Query가 무엇인지, 왜 사용하는지, 그리고 어떻게 사용하는지에 대해 알아보겠습니다.


TanStack Query란 무엇인가요?

TanStack Query는 React, Vue, Solid 등 다양한 프레임워크에서 사용할 수 있는 서버 상태 관리 라이브러리입니다. 주로 서버에서 데이터를 가져오고, 이를 캐싱하며, UI와 동기화하는 작업을 간소화하는 데 사용됩니다.

TanStack Query의 주요 특징

  1. 데이터 캐싱: 서버에서 가져온 데이터를 캐싱하여 불필요한 네트워크 요청을 줄입니다.
  2. 자동 리패칭: 데이터가 오래되었거나 변경되었을 때 자동으로 다시 가져옵니다.
  3. 낙관적 업데이트: 서버 응답을 기다리지 않고 UI를 즉시 업데이트하여 사용자 경험을 개선합니다.
  4. 에러 및 로딩 상태 관리: 데이터 요청 중 발생하는 로딩 및 에러 상태를 간단히 관리할 수 있습니다.
  5. 프리패칭(PreFetching): 사용자가 방문할 가능성이 높은 데이터를 미리 가져와 성능을 최적화합니다.

TanStack Query의 주요 개념

1. 캐싱 라이프사이클

TanStack Query는 데이터를 효율적으로 관리하기 위해 캐싱 라이프사이클을 제공합니다. 이 라이프사이클은 데이터의 상태를 정의하고, 데이터가 언제 다시 패칭되어야 하는지 결정합니다.

캐싱 라이프사이클의 주요 단계
  1. Fresh (신선한 상태):
    • 데이터를 가져온 직후, 데이터는 “Fresh” 상태로 간주됩니다.
    • 이 상태에서는 추가적인 네트워크 요청 없이 캐시된 데이터를 사용합니다.
    • staleTime 옵션을 통해 이 상태의 지속 시간을 설정할 수 있습니다.
  2. Stale (오래된 상태):
    • staleTime이 지나면 데이터는 “Stale” 상태로 간주됩니다.
    • 이 상태에서는 여전히 캐시된 데이터를 사용하지만, 백그라운드에서 데이터를 다시 가져올 수 있습니다.
  3. Inactive (비활성 상태):
    • 쿼리가 더 이상 활성화되지 않으면, 데이터는 “Inactive” 상태로 전환됩니다.
    • 이 상태에서는 캐시된 데이터가 유지되지만, UI에서 사용되지 않습니다.
  4. Garbage Collected (삭제 상태):
    • cacheTime이 지나면 캐시된 데이터는 메모리에서 삭제됩니다.
    • 이 상태에서는 데이터를 다시 사용하려면 네트워크 요청을 통해 새로 가져와야 합니다.

2. useQuery

useQuery는 데이터를 가져오고 캐싱하며, 로딩 및 에러 상태를 관리하는 데 사용됩니다. 주로 읽기 작업(GET 요청)에 사용됩니다.

기본 사용법
const { data, isLoading, error } = useQuery({
  queryKey: ['todos'], // 쿼리 식별자
  queryFn: fetchTodos, // 데이터를 가져오는 함수
}); 
주요 옵션
  1. queryKey
    • 쿼리를 식별하는 고유 키입니다. 배열 형태로 사용하는 것이 권장됩니다.
    • 예: ['todos']['todo', todoId]
  2. queryFn
    • 데이터를 가져오는 비동기 함수입니다.
    • 예: () => fetch('/api/todos').then(res => res.json())
  3. enabled
    • 쿼리 실행 여부를 제어합니다. false로 설정하면 쿼리가 실행되지 않습니다.
    • 예: enabled: !!todoId (조건부 실행)
  4. staleTime
    • 데이터가 fresh 상태로 유지되는 시간(ms)입니다. fresh 상태에서는 리페칭이 발생하지 않습니다.
    • 기본값은 0이며, 예를 들어 staleTime: 1000 * 60 * 5는 5분 동안 데이터를 fresh 상태로 유지합니다.
  5. gcTime
    • 데이터가 inactive 상태가 된 후 가비지 컬렉션(Garbage Collection)을 통해 메모리에서 삭제되기까지 대기하는 시간을 설정합니다.
    • 기본값은 5분이며, 예를 들어 cacheTime: 1000 * 60 * 10은 10분 동안 데이터를 캐시에 유지합니다.
  6. retry
    • 요청 실패 시 재시도 횟수를 설정합니다. false로 설정하면 재시도하지 않습니다.
    • 기본값은 3이며, 예를 들어 retry: 2는 최대 2번 재시도합니다.
  7. retryDelay
    • 재시도 간격(ms 또는 함수)입니다.
    • 기본값은 1000ms이며, 예를 들어 retryDelay: attempt => Math.min(1000 * 2 ** attempt, 30000)은 지수적으로 증가하는 재시도 간격을 설정합니다.
  8. refetchOnWindowFocus
    • 윈도우가 포커스될 때 데이터를 다시 가져올지 여부를 설정합니다.
    • 기본값은 true이며, 예를 들어 refetchOnWindowFocus: false는 포커스 시 리페칭을 비활성화합니다.

3. useMutation

useMutation은 데이터를 생성, 수정, 삭제하는 쓰기 작업(POST, PUT, DELETE 요청)에 사용됩니다. useQuery와 달리 캐싱된 데이터를 자동으로 업데이트하지 않으므로, 수동으로 캐시를 무효화하거나 업데이트해야 합니다.

예제
const { mutate } = useMutation({
    mutationFn: AuthControllerService.logout,
    onSuccess: () => {
      useUserState().logout();
      navigate('/login');
    },
    onError: (error: ApiError) => {
      console.error(error.data.detail);
    },
  });
주요 옵션
  1. mutationFn
    • 데이터를 생성, 수정, 삭제하는 비동기 함수입니다.
  2. onMutate
    • 뮤테이션 실행 직전에 호출되는 함수입니다. 낙관적 업데이트를 구현할 때 유용합니다.
  3. onSuccess
    • 뮤테이션이 성공했을 때 실행되는 함수입니다.
  4. onError
    • 뮤테이션이 실패했을 때 실행되는 함수입니다.

4. staleTimegcTime

TanStack Query는 데이터를 효율적으로 관리하기 위해 staleTimegcTime이라는 두 가지 중요한 옵션을 제공합니다.

staleTime

  • 정의: 데이터가 “Fresh” 상태로 간주되는 시간을 설정합니다.
  • 기본값: 0ms (데이터는 즉시 “Stale” 상태로 간주됨).
  • 사용 예시:
const { data } = useQuery({
  queryKey: ['todos'],
  queryFn: fetchTodos,
  staleTime: 1000 * 60 * 5, // 5분 동안 데이터를 Fresh 상태로 유지
});
  • 활용:
    • 자주 변경되지 않는 데이터를 다룰 때 staleTime을 늘려 네트워크 요청을 줄일 수 있습니다.
    • 예: 제품 목록, 사용자 프로필 등.

gcTime (Garbage Collection Time)

  • 정의: 데이터가 “Inactive” 상태로 전환된 후, 캐시에서 삭제되기까지의 시간을 설정합니다.
  • 기본값: 5분.
  • 사용 예시:
const { data } = useQuery({
  queryKey: ['todos'],
  queryFn: fetchTodos,
  cacheTime: 1000 * 60 * 10, // 10분 동안 캐시 유지
});
  • 활용:
    • 메모리 사용량을 줄이기 위해 gcTime을 짧게 설정할 수 있습니다.
    • 반대로, 자주 재사용되는 데이터를 위해 gcTime을 늘려 네트워크 요청을 줄일 수 있습니다.

5. 데이터를 미리 불러오는 PreFetching

PreFetching은 사용자가 방문할 가능성이 높은 데이터를 미리 가져와 성능을 최적화하는 기법입니다. TanStack Query는 queryClient.prefetchQuery를 통해 PreFetching을 지원합니다.

PreFetching의 장점
  • 사용자가 특정 페이지를 방문하기 전에 데이터를 미리 가져와 로딩 시간을 줄입니다.
  • 사용자 경험(UX)을 크게 개선할 수 있습니다.
사용 예시
import { QueryClient } from '@tanstack/react-query';

const queryClient = new QueryClient();

queryClient.prefetchQuery({
  queryKey: ['todos'],
  queryFn: fetchTodos,
});
활용 사례
  • 페이지 전환: 사용자가 특정 페이지로 이동하기 전에 데이터를 미리 가져옵니다.
  • 호버 이벤트: 사용자가 특정 버튼이나 링크 위에 마우스를 올렸을 때 데이터를 미리 가져옵니다.

6. invalidateQueries

invalidateQueries는 특정 쿼리를 무효화하여 데이터를 다시 가져오도록 강제하는 기능입니다. 데이터가 변경되었거나 오래된 경우, 이를 사용하여 최신 데이터를 가져올 수 있습니다.

사용 예시
import { useQueryClient } from '@tanstack/react-query';

const queryClient = useQueryClient();

function updateTodo() {
  // 데이터 업데이트 후 쿼리 무효화
  queryClient.invalidateQueries(['todos']);
}
활용
  • 데이터 변경 후 동기화:
    • 예: 새로운 데이터를 추가하거나 기존 데이터를 수정한 후, 관련 쿼리를 무효화하여 최신 데이터를 가져옵니다.
  • 조건부 무효화:
    • 특정 조건에 따라 쿼리를 무효화할 수 있습니다.
queryClient.invalidateQueries({
  predicate: query => query.queryKey[0] === 'todos',
});

TanStack Query의 장점

  1. 간단한 API: 데이터 패칭, 캐싱, 동기화, 에러 처리를 간단한 API로 구현할 수 있습니다.
  2. 자동화된 작업: 데이터의 유효성 검사, 캐싱, 리패칭 등이 자동으로 처리됩니다.
  3. 확장성: React뿐만 아니라 Vue, Solid 등 다양한 프레임워크에서 사용할 수 있습니다.
  4. 낙관적 업데이트: 사용자 경험을 개선하는 데 유용합니다.
  5. 커뮤니티 지원: 활발한 커뮤니티와 풍부한 학습 자료를 제공합니다.

마무리

TanStack Query는 서버 상태 관리를 간소화하고, 데이터 패칭과 관련된 복잡한 작업을 자동화하여 개발자 경험을 크게 향상시킵니다. 특히, 데이터 중심의 애플리케이션을 개발할 때 매우 유용합니다.

이 글에서 소개한 내용은 TanStack Query의 기본적인 개념과 사용법에 불과합니다. 더 많은 기능과 고급 사용법은 공식 문서를 참고하세요.

jeewoo jung 아바타