useQuery의 queryKey는 배열
로 지정해줘야 합니다.
문자열만 포함된 배열이 될 수도 있고, 여러 문자열과 중첩된 객체로 구성된 복잡한 형태일 수도 있습니다.
// An individual todo
useQuery({ queryKey: ['todo', 5], ... })
// An individual todo in a "preview" format
useQuery({ queryKey: ['todo', 5, { preview: true }], ...})
useQuery(['todos'], fetchTodos)
// 🚨 잘못된 사용 (query key 중복)
useInfiniteQuery(['todos'], fetchInfiniteTodos)
// ✅ 사용 가능
useInfiniteQuery(['infiniteTodos'], fetchInfiniteTodos)
queryKey
를 기반으로 쿼리 캐싱을 관리하는 것이 핵심입니다.queryClient.setQueryData
등과 같은 특정 쿼리에 접근이 필요한 경우typescript
지원직렬화 가능한 객체가 있는 키 포함, tanstack/query
규칙
import { createQueryKeys } from "@lukemorales/query-key-factory";
export const todos = createQueryKeys('todos', {
detail: (todoId: string) => [todoId],
list: (filters: TodoFilters) => ({
queryKey: [{ filters }],
}),
});
// => createQueryKeys output:
// {
// _def: ['todos'],
// detail: (todoId: string) => {
// queryKey: ['todos', 'todo', todoId],
// },
// list: (filters: TodoFilters) => {
// queryKey: ['todos', 'list', { filters }],
// },
// }
종속적이거나 상위 컨텍스트와 관련된 쿼리 선언을 할 수 있습니다.
export const users = createQueryKeys('users', {
detail: (userId: string) => ({
queryKey: [userId],
queryFn: () => api.getUser(userId),
contextQueries: {
likes: {
queryKey: null,
queryFn: () => api.getUserLikes(userId),
},
},
}),
});
// => createQueryKeys output:
// {
// _def: ['users'],
// detail: (userId: string) => {
// queryKey: ['users', 'detail', userId],
// queryFn: (ctx: QueryFunctionContext) => api.getUser(userId),
// _ctx: {
// likes: {
// queryKey: ['users', 'detail, userId, 'likes'],
// queryFn: (ctx: QueryFunctionContext) => api.getUserLikes(userId),
// },
// },
// },
// }
export function useUserLikes(userId: string) {
return useQuery(users.detail(userId)._ctx.likes);
};
key 접근이 간단하여 캐시를 편리하게 관리하며, 무효화 할 수 있습니다.
users.detail({ status: 'completed' }).queryKey; // => ['users', 'detail', userId]
users.detail._def; // => ['users', 'detail']
import { mergeQueryKeys, inferQueryKeyStore } from "@lukemorales/query-key-factory";
import { users } from './users';
import { todos } from './todos';
export const queries = mergeQueryKeys(users, todos);
export type QueryKeys = inferQueryKeyStore<typeof queries>;
전체 타입의 안정성을 확보하고 useQuery에 전달된 queryKey
에서 QueryFunctionContext
의 타입을 추론하는 것 입니다.
import type { QueryKeys } from "../queries";
// import type { TodosKeys } from "../queries/todos";
type TodosList = QueryKeys['todos']['list'];
// type TodosList = TodosKeys['list'];
const fetchTodos = async (ctx: QueryFunctionContext<TodosList['queryKey']>) => {
const [, , { filters }] = ctx.queryKey;
return api.getTodos({ filters, page: ctx.pageParam });
}
export function useTodos(filters: TodoFilters) {
return useQuery({
...queries.todos.list(filters),
queryFn: fetchTodos,
});
};