TanStack Query 효율을 극대화하는 @lukemorales/query-key-factory 가이드
TanStack Query(React Query)를 사용하는 프로젝트가 커질수록 우리를 가장 괴롭히는 것 중 하나가 바로 Query Key 관리입니다. 문자열 배열로 이루어진 키는 오타에 취약하고, 도메인이 복잡해질수록 어떤 키가 어디에서 사용되는지 파악하기 어려워집니다.
오늘은 이러한 문제를 우아하게 해결해주는 @lukemorales/query-key-factory 라이브러리를 통해, 더 견고한 프런트엔드 아키텍처를 설계하는 방법을 알아보겠습니다.
목차
- Query Key 관리, 왜 중요한가?
- query-key-factory의 핵심 컨셉
- 실전 사용법: 선언부터 적용까지
- 고급 패턴: 종속성 관리와 캐싱 전략
- 개발자 팁: 실수 방지하기
- 자주 묻는 질문(FAQ)
Query Key 관리, 왜 중요한가?
TanStack Query에서 Query Key는 캐시 데이터의 주소와 같습니다. 만약 특정 데이터를 무효화(Invalidation)하거나 수동으로 업데이트하려고 할 때, 키가 일치하지 않으면 캐시는 의도한 대로 동작하지 않습니다.
일반적인 프로젝트에서는 보통 다음과 같은 문제를 겪습니다:
- 오타 문제:
['user', 1]과['users', 1]사이의 미세한 차이로 인한 버그. - 중복 선언: 동일한 엔드포인트에 대한 키가 여러 컴포넌트에 파편화되어 정의됨.
- 타입 안정성 부재: 키에 들어가는 파라미터가 변경되어도 TypeScript가 이를 잡아내지 못함.
query-key-factory는 이러한 휴먼 에러를 원천 차단하고, 중앙 집중화된 키 저장소를 만들 수 있게 도와줍니다.
query-key-factory의 핵심 컨셉
이 라이브러리의 철학은 간단합니다. **“키 선언을 데이터 구조처럼 조직화하라”**는 것입니다. 단순히 배열을 리턴하는 함수를 만드는 것이 아니라, createQueryKeys API를 통해 도메인별로 계층 구조를 만듭니다.
이를 통해 얻는 가장 큰 이점은 **자동 완성(Auto-complete)**입니다. IDE의 도움을 받아 오타 없이 키를 참조할 수 있으며, 키의 구조가 바뀌더라도 한 곳만 수정하면 전체 프로젝트에 반영됩니다.
실전 사용법: 선언부터 적용까지
먼저 라이브러리를 설치합니다.
npm install @lukemorales/query-key-factory
# 또는
yarn add @lukemorales/query-key-factory
1. 키 정의하기 (Queries Factory)
도메인별로 키를 정의합니다. 예를 들어 사용자(Users)와 게시글(Posts) 도메인이 있다고 가정해 보겠습니다.
// src/queries/keys.ts
import { createQueryKeys } from '@lukemorales/query-key-factory';
export const userKeys = createQueryKeys('users', {
all: null, // ['users', 'all']
detail: (userId: string) => ({
queryKey: [userId], // ['users', 'detail', '123']
queryFn: () => fetchUser(userId), // queryFn도 함께 관리 가능!
}),
});
export const postKeys = createQueryKeys('posts', {
list: (filters: { category: string; search?: string }) => ({
queryKey: [filters], // ['posts', 'list', { category, search }]
}),
});
2. 컴포넌트에서 사용하기
이제 정의한 팩토리를 useQuery에 적용합니다.
import { useQuery } from '@tanstack/react-query';
import { userKeys } from '../queries/keys';
export const UserProfile = ({ id }: { id: string }) => {
const { data } = useQuery({
...userKeys.detail(id), // queryKey와 queryFn이 한꺼번에 주입됨
});
return <div>{data?.name}</div>;
};
고급 패턴: 종속성 관리와 캐싱 전략
실무에서는 특정 데이터가 변경되었을 때 관련 있는 여러 캐시를 한꺼번에 날려야 하는 경우가 많습니다. query-key-factory는 계층적 구조를 지원하므로 이를 매우 쉽게 처리할 수 있습니다.
예를 들어, userKeys.all은 해당 도메인의 모든 키를 포함하는 상위 개념입니다. queryClient.invalidateQueries(userKeys._def)를 실행하면 해당 팩토리에 정의된 모든 하위 키(detail, list 등)가 무효화됩니다.
개발자의 팁:
_def속성 활용하기 팩토리 객체의_def속성은 해당 스코프의 루트 키를 의미합니다. 전체 도메인을 초기화하고 싶을 때는 개별 키를 일일이 나열하지 말고_def를 사용하세요. 이는 유지보수 시 누락되는 키가 없도록 보장해줍니다.
자주 묻는 질문(FAQ)
Q: 모든 쿼리 키를 한 곳에서 관리해야 하나요?
A: 규모가 작은 프로젝트라면 한 파일에서 관리해도 무방하지만, 규모가 커지면 도메인 단위(예: users.keys.ts, orders.keys.ts)로 파일을 분리한 뒤 mergeQueryKeys 기능을 사용하여 통합하는 것을 추천합니다.
Q: queryFn을 반드시 팩토리에 포함해야 하나요?
A: 필수는 아닙니다. 하지만 팩토리에 queryFn을 포함하면 useQuery 호출 시 코드가 훨씬 간결해지며, 키와 함수 사이의 강한 결합을 통해 데이터 일관성을 지키기 쉬워집니다.
Q: 기존 프로젝트에 점진적으로 도입할 수 있나요?
A: 네, 가능합니다. 기존의 문자열 기반 키와 혼용해서 사용할 수 있으므로, 새로운 기능을 구현하거나 복잡한 필터링이 필요한 도메인부터 우선적으로 적용해 보세요.
더 자세한 정보와 고급 활용법은 @lukemorales/query-key-factory 공식 저장소에서 확인하실 수 있습니다. 이 라이브러리를 통해 여러분의 TanStack Query 코드가 한층 더 견고해지길 바랍니다!