queryKey는 편의상 Key라고 지칭했습니다.
Key
가 직렬화되어 있으며, 해쉬되어 관리됩니다.useQuery(['todos', { status, page }], ...)
useQuery(['todos', { page, status }], ...)
useQuery(['todos', { page, status, other: undefined }], ...)
useQuery(['todos', status, page], ...)
useQuery(['todos', page, status], ...)
useQuery(['todos', undefined, page, status], ...)
Key
는 쿼리에 대해 유니크 값- React Query는 cache에
Key
를 이용해 접근useQuery
및useInfiniteQuery
에 동일한Key
를 사용할 수 없음 ➡ 하나의query cache
만 유효
useQuery(['todos'], fetchTodos)
// 🚨 잘못된 사용 (query key 중복)
useInfiniteQuery(['todos'], fetchInfiniteTodos)
// ✅ 사용 가능
useInfiniteQuery(['infiniteTodos'], fetchInfiniteTodos)
tanstak/query
의 Key
는 배열로 선언함 // 🚨 will be transformed to ['todos'] anyhow
useQuery('todos')
// ✅
useQuery(['todos'])
Kent C. Dodds의 Colocation을 통한 Maintenability
기능 디렉터리에 있는 해당 쿼리 옆에 쿼리 키를 보관해보자.
- src
- features
- Profile
- index.tsx
- queries.ts
- Todos
- index.tsx
- queries.ts
github : lukemorales/query-key-factory
typescript
지원key
네이밍queryKey
와 queryFn
을 함께 선언하고 쿼리를 실행하는데 간단하게 사용 가능@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']
Key
에 접근할 수 있음// queries/users.ts
export const users = createQueryKeys('users', {
all: null,
detail: (userId: string) => ({
queryKey: [userId],
queryFn: () => api.getUser(userId),
}),
});
// queries/todos.ts
export const todos = createQueryKeys('todos', {
detail: (todoId: string) => [todoId],
list: (filters: TodoFilters) => ({
queryKey: [{ filters }],
queryFn: (ctx) => api.getTodos({ filters, page: ctx.pageParam }),
}),
});
// queries/index.ts
export const queries = mergeQueryKeys(users, todos);
// queries/index.ts
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>;
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,
});
};
// 🕺 remove everything related to the todos feature
queryClient.removeQueries(queries.posts.getPosts(page, limit).queryKey)
// 🚀 invalidate all the lists
queryClient.invalidateQueries(queries.posts.getPosts(page, limit).queryKey)
// 🙌 prefetch a single todo
queryClient.prefetchQueries(queries.posts.getPosts(page, limit).queryKey, () => useGetPosts(page, limit))
참조 링크