React Query(Tanstack Query)를 사용하던 중 query key를 단순하게 사용하다 보니 key 관리가 제대로 되지 않아 쿼리 무효화(invalidateQueries)를 할 때 query key를 일일이 확인해야 하는 번거로움이 있었다.
이 번거로움을 없애기 위해 Tanstack Query의 메인테이너인 TkDodo의 블로그를 확인하여 해결할 수 있었다.
At its core, TanStack Query manages query caching for you based on query keys. Query keys have to be an Array at the top level, and can be as simple as an Array with a single string, or as complex as an array of many strings and nested objects. As long as the query key is serializable, and unique to the query's data, you can use it!
요약하자면, TanStack Query는 쿼리 키를 기반으로 쿼리 캐싱을 관리합니다. 쿼리 키는 최상위 레벨에서 배열 형태여야 하며, 단일 문자열로 이루어진 배열에서부터 여러 문자열과 중첩된 객체로 이루어진 복잡한 배열까지 가능합니다. 쿼리 키가 직렬화 가능하고 쿼리 데이터에 대해 고유하다면 사용할 수 있습니다!
useQuery({ queryKey: ['todos'], ... })
useQuery({ queryKey: ['todos', idx], ... })
위와 같은 방식에 대한 문제를 느끼게 되어 query key를 한꺼번에 관리할 수 있는 파일이 필요하다는 생각이 들었다.
TkDodo의 블로그에서는 다른 폴더를 만들지 않고 아래와 같은 폴더 구조를 추천했으나 여러 컴포넌트에서 query key 사용이 필요하다는 생각이 들어 다르게 폴더 구조를 생각했다.
// TkDodo
- src
- features
- Profile
- index.tsx
- queries.ts
- Todos
- index.tsx
- queries.ts
- src
- queries
- todoKeys.ts
// todoKeys.ts
export const todoKeys = {
all: ['todos'] as const,
lists: () => [...todoKeys.all, 'list'] as const,
list: (idx: string) => [...todoKeys.lists(), idx] as const,
details: () => [...todoKeys.all, 'detail'] as const,
detail: (id: number) => [...todoKeys.details(), id] as const,
}
// useQuery
const { data } = useQuery({
queryKey: todoKeys.list(idx),
queryFn: () => fetchTodos(idx),
})
// useMutation
const queryClient = useQueryClient();
const { mutate } = useMutation({
mutationFn: fetchTodos(idx),
onSuccess: () => {
queryClient.invalidateQueries(todoKeys.Lists())
}
모든 쿼리 키를 무효화하기 원한다면 queryClient.invalidateQueries(todoKeys.all)
를 사용해도 상관없다.
query key를 일일이 확인해야 하는 번거로움을 없애고 여러 명이서 프로젝트를 진행할 때 query key를 다르게 사용하는 것을 방지할 수 있어 장점이 많다고 생각이 들었다.
reference
https://tanstack.com/query/v4/docs/react/guides/query-keys
https://tkdodo.eu/blog/effective-react-query-keys
https://develogger.kro.kr/blog/LKHcoding/153