🔥 쿼리 키

378자
5분

TanStack Query는 쿼리 키를 기반으로 쿼리 캐싱을 관리합니다. 쿼리 키는 최상위 레벨에서 반드시 배열이어야 하며, 단일 문자열로 구성된 간단한 배열부터 여러 문자열과 중첩된 객체로 이루어진 복잡한 배열까지 다양한 형태를 가질 수 있습니다. 쿼리 키가 직렬화 가능하고 쿼리의 데이터에 대해 고유하다면 어떤 형태든 사용할 수 있습니다!

간단한 쿼리 키

가장 기본적인 형태의 키는 상수 값으로 구성된 배열입니다. 이러한 형식은 다음과 같은 경우에 유용합니다:

  • 일반적인 목록/인덱스 리소스
  • 계층 구조가 없는 리소스
// 할 일 목록
useQuery({ queryKey: ['todos'], ... })
 
// 다른 특별한 것
useQuery({ queryKey: ['something', 'special'], ... })
 
typescript

변수가 포함된 배열 키

쿼리가 데이터를 고유하게 설명하기 위해 더 많은 정보가 필요한 경우, 문자열과 직렬화 가능한 객체를 조합한 배열을 사용할 수 있습니다. 이는 다음과 같은 경우에 유용합니다:

  • 계층적이거나 중첩된 리소스
    • 항목을 고유하게 식별하기 위해 ID, 인덱스 또는 다른 기본 값을 전달하는 것이 일반적입니다
  • 추가 매개변수가 있는 쿼리
    • 추가 옵션 객체를 전달하는 것이 일반적입니다
// 개별 할 일
useQuery({ queryKey: ['todo', 5], ... })
 
// '미리보기' 형식의 개별 할 일
useQuery({ queryKey: ['todo', 5, { preview: true }], ...})
 
// '완료된' 할 일 목록
useQuery({ queryKey: ['todos', { type: 'done' }], ... })
 
typescript

쿼리 키는 결정론적으로 해시됩니다!

이는 객체 내 키의 순서에 관계없이 다음의 모든 쿼리가 동일하게 취급된다는 것을 의미합니다:

useQuery({ queryKey: ['todos', { status, page }], ... })
useQuery({ queryKey: ['todos', { page, status }], ...})
useQuery({ queryKey: ['todos', { page, status, other: undefined }], ... })
 
typescript

하지만 다음 쿼리 키들은 서로 다릅니다. 배열 항목의 순서가 중요합니다!

useQuery({ queryKey: ['todos', status, page], ... })
useQuery({ queryKey: ['todos', page, status], ...})
useQuery({ queryKey: ['todos', undefined, page, status], ...})
 
typescript

쿼리 함수가 변수에 의존한다면 해당 변수를 쿼리 키에 포함하세요

쿼리 키는 가져오는 데이터를 고유하게 설명하기 때문에, 쿼리 함수에서 사용하는 변수 중 변경되는 모든 변수를 포함해야 합니다. 예를 들어:

function Todos({ todoId }) {
  const result = useQuery({
    queryKey: ['todos', todoId],
    queryFn: () => fetchTodoById(todoId),
  })
}
 
typescript

쿼리 키는 쿼리 함수의 의존성 역할을 한다는 점에 주목하세요. 의존하는 변수를 쿼리 키에 추가하면 쿼리가 독립적으로 캐시되고, 변수가 변경될 때마다 쿼리가 자동으로 다시 가져와집니다(staleTime 설정에 따라 다름). 자세한 정보와 예제는 exhaustive-deps 섹션을 참조하세요.

추가 읽을거리

대규모 애플리케이션에서 쿼리 키를 조직화하는 팁은 효과적인 React Query 키를 확인하고 커뮤니티 리소스의 쿼리 키 팩토리 패키지를 살펴보세요.