Query Key

이재철·2024년 1월 14일
0

tanstack-query-v5

목록 보기
2/4
post-custom-banner

기본 개념

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 등과 같은 특정 쿼리에 접근이 필요한 경우
    초기 설정한 포맷을 지켜야 재대로 쿼리에 접근할 수 있습니다.

Query Key Factory

Query Key Factory

  • typescript 지원
  • 규칙성 있는 KEY 네이밍
  • 모든 키는 직렬화 가능한 객체가 있는 키를 포함
  • 간단하게 사용

표준화 된 키

직렬화 가능한 객체가 있는 키 포함, 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 접근

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>;

QueryFunctionContext 편리한 사용

전체 타입의 안정성을 확보하고 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,
  });
};
profile
혼신의 힘을 다하다 🤷‍♂️
post-custom-banner

0개의 댓글