
FrontEnd 개발에서 데이터 fetching과 상태 관리는 필수적인 작업입니다. 특히, 서버와의 통신이 빈번한 애플리케이션에서는 데이터의 캐싱, 동기화, 에러 처리와 같은 작업이 복잡해질 수 있습니다. 이런 문제를 해결하기 위해 등장한 라이브러리가 바로 TanStack Query입니다. 이 포스트에서는 TanStack Query가 무엇인지, 왜 사용하는지, 그리고 어떻게 사용하는지에 대해 알아보겠습니다.
TanStack Query란 무엇인가요?
TanStack Query는 React, Vue, Solid 등 다양한 프레임워크에서 사용할 수 있는 서버 상태 관리 라이브러리입니다. 주로 서버에서 데이터를 가져오고, 이를 캐싱하며, UI와 동기화하는 작업을 간소화하는 데 사용됩니다.
TanStack Query의 주요 특징
- 데이터 캐싱: 서버에서 가져온 데이터를 캐싱하여 불필요한 네트워크 요청을 줄입니다.
- 자동 리패칭: 데이터가 오래되었거나 변경되었을 때 자동으로 다시 가져옵니다.
- 낙관적 업데이트: 서버 응답을 기다리지 않고 UI를 즉시 업데이트하여 사용자 경험을 개선합니다.
- 에러 및 로딩 상태 관리: 데이터 요청 중 발생하는 로딩 및 에러 상태를 간단히 관리할 수 있습니다.
- 프리패칭(PreFetching): 사용자가 방문할 가능성이 높은 데이터를 미리 가져와 성능을 최적화합니다.
TanStack Query의 주요 개념
1. 캐싱 라이프사이클
TanStack Query는 데이터를 효율적으로 관리하기 위해 캐싱 라이프사이클을 제공합니다. 이 라이프사이클은 데이터의 상태를 정의하고, 데이터가 언제 다시 패칭되어야 하는지 결정합니다.
캐싱 라이프사이클의 주요 단계
- Fresh (신선한 상태):
- 데이터를 가져온 직후, 데이터는 “Fresh” 상태로 간주됩니다.
- 이 상태에서는 추가적인 네트워크 요청 없이 캐시된 데이터를 사용합니다.
staleTime
옵션을 통해 이 상태의 지속 시간을 설정할 수 있습니다.
- Stale (오래된 상태):
staleTime
이 지나면 데이터는 “Stale” 상태로 간주됩니다.- 이 상태에서는 여전히 캐시된 데이터를 사용하지만, 백그라운드에서 데이터를 다시 가져올 수 있습니다.
- Inactive (비활성 상태):
- 쿼리가 더 이상 활성화되지 않으면, 데이터는 “Inactive” 상태로 전환됩니다.
- 이 상태에서는 캐시된 데이터가 유지되지만, UI에서 사용되지 않습니다.
- Garbage Collected (삭제 상태):
cacheTime
이 지나면 캐시된 데이터는 메모리에서 삭제됩니다.- 이 상태에서는 데이터를 다시 사용하려면 네트워크 요청을 통해 새로 가져와야 합니다.
2. useQuery
useQuery
는 데이터를 가져오고 캐싱하며, 로딩 및 에러 상태를 관리하는 데 사용됩니다. 주로 읽기 작업(GET 요청)에 사용됩니다.
기본 사용법
const { data, isLoading, error } = useQuery({
queryKey: ['todos'], // 쿼리 식별자
queryFn: fetchTodos, // 데이터를 가져오는 함수
});
주요 옵션
queryKey
- 쿼리를 식별하는 고유 키입니다. 배열 형태로 사용하는 것이 권장됩니다.
- 예:
['todos']
,['todo', todoId]
queryFn
- 데이터를 가져오는 비동기 함수입니다.
- 예:
() => fetch('/api/todos').then(res => res.json())
enabled
- 쿼리 실행 여부를 제어합니다.
false
로 설정하면 쿼리가 실행되지 않습니다. - 예:
enabled: !!todoId
(조건부 실행)
- 쿼리 실행 여부를 제어합니다.
staleTime
- 데이터가 fresh 상태로 유지되는 시간(ms)입니다. fresh 상태에서는 리페칭이 발생하지 않습니다.
- 기본값은
0
이며, 예를 들어staleTime: 1000 * 60 * 5
는 5분 동안 데이터를 fresh 상태로 유지합니다.
gcTime
- 데이터가 inactive 상태가 된 후 가비지 컬렉션(Garbage Collection)을 통해 메모리에서 삭제되기까지 대기하는 시간을 설정합니다.
- 기본값은
5분
이며, 예를 들어cacheTime: 1000 * 60 * 10
은 10분 동안 데이터를 캐시에 유지합니다.
retry
- 요청 실패 시 재시도 횟수를 설정합니다.
false
로 설정하면 재시도하지 않습니다. - 기본값은
3
이며, 예를 들어retry: 2
는 최대 2번 재시도합니다.
- 요청 실패 시 재시도 횟수를 설정합니다.
retryDelay
- 재시도 간격(ms 또는 함수)입니다.
- 기본값은
1000ms
이며, 예를 들어retryDelay: attempt => Math.min(1000 * 2 ** attempt, 30000)
은 지수적으로 증가하는 재시도 간격을 설정합니다.
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);
},
});
주요 옵션
mutationFn
- 데이터를 생성, 수정, 삭제하는 비동기 함수입니다.
onMutate
- 뮤테이션 실행 직전에 호출되는 함수입니다. 낙관적 업데이트를 구현할 때 유용합니다.
onSuccess
- 뮤테이션이 성공했을 때 실행되는 함수입니다.
onError
- 뮤테이션이 실패했을 때 실행되는 함수입니다.
4. staleTime
과 gcTime
TanStack Query는 데이터를 효율적으로 관리하기 위해 staleTime
과 gcTime
이라는 두 가지 중요한 옵션을 제공합니다.
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의 장점
- 간단한 API: 데이터 패칭, 캐싱, 동기화, 에러 처리를 간단한 API로 구현할 수 있습니다.
- 자동화된 작업: 데이터의 유효성 검사, 캐싱, 리패칭 등이 자동으로 처리됩니다.
- 확장성: React뿐만 아니라 Vue, Solid 등 다양한 프레임워크에서 사용할 수 있습니다.
- 낙관적 업데이트: 사용자 경험을 개선하는 데 유용합니다.
- 커뮤니티 지원: 활발한 커뮤니티와 풍부한 학습 자료를 제공합니다.
마무리
TanStack Query는 서버 상태 관리를 간소화하고, 데이터 패칭과 관련된 복잡한 작업을 자동화하여 개발자 경험을 크게 향상시킵니다. 특히, 데이터 중심의 애플리케이션을 개발할 때 매우 유용합니다.
이 글에서 소개한 내용은 TanStack Query의 기본적인 개념과 사용법에 불과합니다. 더 많은 기능과 고급 사용법은 공식 문서를 참고하세요.
