무엇
QueryCache는 쿼리의 데이터·메타 정보·상태가 실제로 담기는 저장소다. QueryClient가 내부에 하나 들고 있으며, 앱 코드가 직접 다룰 일은 드물다.
보통은 QueryClient의 메서드(invalidateQueries, getQueryData 등)로 캐시를 다루고, QueryCache 자체를 만질 일은 거의 없다. 인스턴스가 필요하면 queryClient.getQueryCache()로 얻는다.
const queryCache = queryClient.getQueryCache()
직접 생성해 QueryClient에 주입할 수도 있는데, 주로 전역 콜백을 붙일 때 그렇게 한다.
import { QueryCache, QueryClient } from '@tanstack/react-query'
const queryCache = new QueryCache({
onError: (error, query) => {
console.error(`쿼리 실패 [${query.queryKey}]:`, error)
},
})
const queryClient = new QueryClient({ queryCache })
무슨 일이 일어나나
useQuery로 만들어진 모든 쿼리는 이 캐시에 쿼리 키로 저장된다. 같은 키를 쓰는 컴포넌트끼리 하나의 캐시 항목을 공유하는 것도 여기서 이뤄진다. 각 항목은 데이터뿐 아니라 상태(pending/error/success), 마지막 갱신 시각, 관찰자 수 같은 메타 정보를 함께 들고 있다.
생성자에 넘긴 콜백은 전역으로 동작한다. onError는 어떤 쿼리가 실패하든 한 번씩 불린다. 개별 쿼리마다 에러를 처리하는 대신, 실패를 한 곳에서 잡아 로깅하거나 토스트를 띄우고 싶을 때 쓴다.
사용법
전역 에러 처리가 가장 흔한 용도다. 각 콜백은 (error, query) 형태로 실패한 쿼리 인스턴스까지 받는다.
import { QueryCache, QueryClient } from '@tanstack/react-query'
const queryClient = new QueryClient({
queryCache: new QueryCache({
onError: (error, query) => {
// meta에 조용히 실패시킬 쿼리 표시를 둘 수도 있다
if (query.meta?.silent) return
toast.error(`데이터를 불러오지 못했습니다`)
},
}),
})
캐시를 직접 들여다봐야 할 때는 find/findAll로 쿼리 인스턴스를 꺼낸다. find는 필터에 맞는 하나(Query | undefined), findAll은 여럿(Query[])을 돌려준다. subscribe(callback)은 캐시가 바뀔 때마다 이벤트를 받는 구독이고, 해제 함수를 돌려준다. clear()는 캐시를 통째로 비운다.
const cache = queryClient.getQueryCache()
const todo = cache.find({ queryKey: ['todo', 1] }) // 하나
const all = cache.findAll({ queryKey: ['todos'] }) // 여럿
const unsubscribe = cache.subscribe((event) => {
console.log(event.type, event.query.queryKey)
})
실무 예시
에러 처리를 컴포넌트마다 반복하지 않고 QueryCache에 한 번 몰아 두는 패턴이다. 쿼리별로 다르게 처리해야 하면 meta에 표시를 심어 콜백에서 분기한다.
const queryClient = new QueryClient({
queryCache: new QueryCache({
onError: (error, query) => {
// meta.errorMessage가 있으면 그 문구로, 없으면 기본 처리
const message = (query.meta?.errorMessage as string) ?? '요청 실패'
toast.error(message)
},
}),
})
// 개별 쿼리에서
useQuery({
queryKey: ['profile'],
queryFn: fetchProfile,
meta: { errorMessage: '프로필을 불러오지 못했습니다' },
})
왜 중요한가
QueryCache는 개념을 이해하는 데는 중요하지만, 직접 조작할 일은 많지 않다 — 대부분의 캐시 작업은 QueryClient가 더 안전한 상위 API로 감싸 두었다. 실무에서 QueryCache를 직접 쓰는 거의 유일한 이유는 onError 같은 전역 콜백을 달 때다. "캐시는 QueryClient가 아니라 이 안에 있다"는 구조만 알아 두면, 캐시가 어떻게 공유되고 언제 비워지는지 이해하는 밑바탕이 된다.
Reference