🔥 쿼리 키

378자
5분

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

간단한 쿼리 키

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

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

변수가 포함된 배열 키

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

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

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

typescript
useQuery({ queryKey: ['todos', status, page], ... })
useQuery({ queryKey: ['todos', page, status], ...})
useQuery({ queryKey: ['todos', undefined, page, status], ...})
 
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
function Todos({ todoId }) {
  const result = useQuery({
    queryKey: ['todos', todoId],
    queryFn: () => fetchTodoById(todoId),
  })
}
 

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

추가 읽을거리

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

YouTube 영상

채널 보기
벡터의 정의와 덧셈 연산 | 선형대수학
숫자 하나가 AI 모델의 운명을 바꾼다? | 선형대수학
숫자 하나가 AI 모델의 운명을 바꾼다? | 선형대수학
13편, 인덱스가 많으면 왜 느려질까? 쓰기 증폭과 인덱스 튜닝의 이해
마지막편, 트라이 노드를 50% 이상 줄이는 방법? 압축 트라이 성능 분석 | Trie 자료구조 이야기
BTree 노드의 구조는?
트라이(Trie) 자료구조: 파이썬으로 삽입(Insert) 연산 구현하기 | Trie 자료구조 이야기
트라이(Trie)에서 단어를 삭제하는 방법 | Trie 자료구조 이야기