🔥 쿼리 무효화

483자
6분

쿼리가 오래되기를 기다렸다가 다시 가져오는 방식은 항상 효과적이지 않습니다. 특히 사용자의 행동으로 인해 쿼리 데이터가 더 이상 유효하지 않다는 것을 확실히 알고 있을 때는 더욱 그렇습니다. 이런 상황을 위해 QueryClient는 invalidateQueries 메서드를 제공합니다. 이 메서드를 사용하면 쿼리를 오래된 것으로 표시하고 필요에 따라 다시 가져올 수 있습니다.

// 캐시의 모든 쿼리를 무효화
queryClient.invalidateQueries()
// 'todos'로 시작하는 키를 가진 모든 쿼리를 무효화
queryClient.invalidateQueries({ queryKey: ['todos'] })
 
typescript

다른 라이브러리들이 정규화된 캐시를 사용하여 명령적으로 또는 스키마 추론을 통해 로컬 쿼리를 새 데이터로 업데이트하려고 시도하는 반면, TanStack Query는 정규화된 캐시 유지에 따르는 수동 작업을 피할 수 있는 도구를 제공합니다. 대신 목표를 정한 무효화, 백그라운드 재가져오기, 그리고 궁극적으로 원자적 업데이트를 수행하는 방식을 권장합니다.

invalidateQueries로 쿼리를 무효화하면 두 가지 일이 발생합니다:

  1. 쿼리가 오래된 것으로 표시됩니다. 이 오래된 상태는 useQuery나 관련 훅에서 사용 중인 어떤 staleTime 설정보다 우선합니다.
  2. 현재 useQuery나 관련 훅을 통해 렌더링되고 있는 쿼리라면, 백그라운드에서 다시 가져옵니다.

invalidateQueries를 사용한 쿼리 매칭

invalidateQueriesremoveQueries 같은 API를 사용할 때(그리고 부분 쿼리 매칭을 지원하는 다른 API들을 사용할 때), 접두사로 여러 쿼리를 매칭하거나 정확한 쿼리를 매칭할 수 있습니다. 사용할 수 있는 필터 유형에 대한 자세한 정보는 쿼리 필터를 참조하세요.

다음 예제에서는 'todos' 접두사를 사용하여 쿼리 키가 'todos'로 시작하는 모든 쿼리를 무효화할 수 있습니다:

import { useQuery, useQueryClient } from '@tanstack/react-query'
 
// 컨텍스트에서 QueryClient 가져오기
const queryClient = useQueryClient()
 
queryClient.invalidateQueries({ queryKey: ['todos'] })
 
// 아래의 두 쿼리 모두 무효화됩니다
const todoListQuery = useQuery({
  queryKey: ['todos'],
  queryFn: fetchTodoList,
})
const todoListQuery = useQuery({
  queryKey: ['todos', { page: 1 }],
  queryFn: fetchTodoList,
})
 
typescript

invalidateQueries 메서드에 더 구체적인 쿼리 키를 전달하여 특정 변수를 가진 쿼리만 무효화할 수도 있습니다:

queryClient.invalidateQueries({
  queryKey: ['todos', { type: 'done' }],
})
 
// 아래 쿼리는 무효화됩니다
const todoListQuery = useQuery({
  queryKey: ['todos', { type: 'done' }],
  queryFn: fetchTodoList,
})
 
// 하지만 아래 쿼리는 무효화되지 않습니다
const todoListQuery = useQuery({
  queryKey: ['todos'],
  queryFn: fetchTodoList,
})
 
typescript

invalidateQueries API는 매우 유연합니다. 추가 변수나 하위 키가 없는 'todos' 쿼리만 무효화하고 싶다면, invalidateQueries 메서드에 exact: true 옵션을 전달할 수 있습니다:

queryClient.invalidateQueries({
  queryKey: ['todos'],
  exact: true,
})
 
// 아래 쿼리는 무효화됩니다
const todoListQuery = useQuery({
  queryKey: ['todos'],
  queryFn: fetchTodoList,
})
 
// 하지만 아래 쿼리는 무효화되지 않습니다
const todoListQuery = useQuery({
  queryKey: ['todos', { type: 'done' }],
  queryFn: fetchTodoList,
})
 
typescript

더 세밀한 제어가 필요하다면, invalidateQueries 메서드에 술어 함수를 전달할 수 있습니다. 이 함수는 쿼리 캐시의 각 Query 인스턴스를 받아 해당 쿼리를 무효화할지 여부를 true 또는 false로 반환합니다:

queryClient.invalidateQueries({
  predicate: (query) =>
    query.queryKey[0] === 'todos' && query.queryKey[1]?.version >= 10,
})
 
// 아래 쿼리는 무효화됩니다
const todoListQuery = useQuery({
  queryKey: ['todos', { version: 20 }],
  queryFn: fetchTodoList,
})
 
// 아래 쿼리도 무효화됩니다
const todoListQuery = useQuery({
  queryKey: ['todos', { version: 10 }],
  queryFn: fetchTodoList,
})
 
// 하지만 아래 쿼리는 무효화되지 않습니다
const todoListQuery = useQuery({
  queryKey: ['todos', { version: 5 }],
  queryFn: fetchTodoList,
})
 
typescript

이렇게 invalidateQueries를 사용하면 쿼리의 상태를 효과적으로 관리하고, 필요할 때 데이터를 새로 가져올 수 있습니다. 이는 애플리케이션의 데이터 일관성을 유지하는 데 매우 유용한 도구입니다.