무엇
useQueryClient는 컨텍스트에 올라간 QueryClient 인스턴스를 꺼내 오는 훅이다. 이 인스턴스로 캐시를 직접 읽고 쓰고 무효화한다.
인자 없이 부르면 트리 위쪽 QueryClientProvider의 인스턴스를 돌려준다. 커스텀 인스턴스를 명시적으로 넘길 수도 있다.
const queryClient = useQueryClient()
// 또는 특정 인스턴스를 지정
const queryClient = useQueryClient(customClient)
무슨 일이 일어나나
QueryClient는 앱 전체의 캐시를 쥐고 있는 객체다. 보통 앱 최상단에서 한 번 만들어 QueryClientProvider로 내려 준다. useQueryClient는 그렇게 내려온 인스턴스를 컴포넌트 안에서 집어 오는 통로일 뿐이다 — 새 클라이언트를 만들지 않고, 이미 있는 것을 참조한다.
이 인스턴스가 필요한 이유는, 훅(useQuery·useMutation) 바깥에서 캐시를 조작해야 할 때가 있기 때문이다. 뮤테이션 성공 후 목록을 새로고침하거나, 낙관적 업데이트로 캐시를 미리 바꾸거나, 다음 화면 데이터를 미리 받아 두는(prefetch) 일이 그렇다.
자주 쓰는 메서드는 다음과 같다.
invalidateQueries({ queryKey }): 해당 쿼리를 stale로 표시하고 활성 쿼리를 다시 가져오게 한다.getQueryData(queryKey)/setQueryData(queryKey, updater): 캐시 값을 직접 읽고 쓴다.cancelQueries({ queryKey }): 진행 중인 리페치를 취소한다(낙관적 업데이트 전에 경합 방지).prefetchQuery({ queryKey, queryFn }): 데이터를 미리 받아 캐시에 채운다.removeQueries({ queryKey })/refetchQueries({ queryKey }): 캐시에서 제거하거나 강제로 다시 가져온다.
사용법
가장 흔한 쓰임은 뮤테이션 뒤 무효화다. 서버를 바꿨으니 관련 쿼리를 stale로 만들어 화면을 최신으로 맞춘다.
import { useMutation, useQueryClient } from '@tanstack/react-query'
export function useAddTodo() {
const queryClient = useQueryClient()
return useMutation({
mutationFn: postTodo,
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['todos'] })
},
})
}
캐시를 직접 읽고 쓰는 것도 이 인스턴스로 한다. 예를 들어 목록에서 이미 받은 항목을 상세 화면의 초기값으로 재사용할 수 있다.
const cached = queryClient.getQueryData<Todo[]>(['todos'])
const one = cached?.find((t) => t.id === id)
실무 예시
링크에 마우스를 올렸을 때 상세 데이터를 미리 받아 두는 프리페치다. 실제 이동 시 데이터가 이미 캐시에 있어 로딩이 사라진다.
import { useQueryClient } from '@tanstack/react-query'
export function TodoLink({ id }: { id: string }) {
const queryClient = useQueryClient()
const prefetch = () => {
queryClient.prefetchQuery({
queryKey: ['todo', id],
queryFn: () => fetchTodo(id),
staleTime: 10_000, // 이 시간 내 재요청은 생략
})
}
return <a href={`/todos/${id}`} onMouseEnter={prefetch}>열기</a>
}
왜 중요한가
useQuery·useMutation이 선언형으로 대부분을 처리하지만, 캐시를 명령형으로 만져야 하는 순간이 반드시 온다 — 무효화, 낙관적 업데이트, 프리페치, 캐시 직접 조작. useQueryClient는 그 순간의 진입점이다. 특히 뮤테이션 후 무효화는 TanStack Query를 쓰는 거의 모든 앱에서 반복되는 패턴이라, useMutation과 함께 손에 익혀야 하는 훅이다.
Reference