Skip to content

Tanstack Query 사용법

Jimyu edited this page Jul 25, 2025 · 4 revisions

쿼리 키 설정법

TanStack Query에서 queryKey는 쉽게 생각하면 "데이터의 이름표" 같은 개념!


1. 쿼리 키(Query Key)란?

TanStack Query는 서버에서 가져오는 데이터를 저장하고 관리한다.
이때 데이터가 여러 가지면 헷갈리기 때문에 각 데이터마다 이름표인 queryKey를 붙여서 구분하는 것!

예시

  • 학생 목록 데이터['students']
  • 특정 학생 상세 정보(학생 ID가 5번인 경우)['student', 5]

이렇게 이름표가 다르면 TanStack Query가 캐시를 따로 관리해줘서 데이터 꼬임 없이 사용 가능


2. 쿼리 키를 만드는 기준

  1. 데이터 주제(엔티티) 중심으로 만들기

    • 예: users, posts, comments
  2. 필요하면 세부 조건 추가

    • 예: 특정 ID, 필터 값, 페이지 번호 등
  3. 배열 형태로 구조화

    • TanStack Query는 배열을 쓰는 걸 권장해. 예: ['posts', postId], ['comments', { postId, page: 2 }]

⚠️ 이때 키의 순서가 중요!! 아래 쿼리키들은 순서가 다르므로 모두 다르게 본다

// An individual todo
useQuery({ queryKey: ['todo', 5], ... })

// An individual todo in a "preview" format
useQuery({ queryKey: ['todo', 5, { preview: true }], ...})

// A list of todos that are "done"
useQuery({ queryKey: ['todos', { type: 'done' }], ... })

4. QueryKey.ts 예시

// QueryKey.ts
export const QUERY_KEYS = {
  // 기본 리스트
  STUDENTS: ['students'] as const,
  POSTS: ['posts'] as const,

  // 세부 항목 (함수로 ID 넘겨주기)
  studentDetail: (id: number) => ['student', id] as const,
  postDetail: (id: number) => ['post', id] as const,

  // 조건 있는 경우
  comments: (postId: number, page: number) =>
    ['comments', { postId, page }] as const,
};

5. 사용 예시

import { useQuery } from '@tanstack/vue-query'
import { QUERY_KEYS } from './QueryKey'

// 학생 목록 불러오기
const { data: students } = useQuery({
  queryKey: QUERY_KEYS.STUDENTS,
  queryFn: fetchStudents,
})

// 특정 학생 불러오기
const { data: studentDetail } = useQuery({
  queryKey: QUERY_KEYS.studentDetail(5),
  queryFn: () => fetchStudentDetail(5),
})

6. 정리

  • queryKey = 데이터 이름표
  • 배열 형태로 만들고, 조건(아이디나 페이지) 있으면 두 번째 요소로 추가
  • 한 파일에 모아서 관리하면 유지보수가 편해짐

API 호출에서 사용하는 방법

핵심 패턴 정리

  1. useQuery → GET 전용 (데이터 불러오기)
  2. useMutation → POST/PUT/PATCH/DELETE (데이터 변경)
  3. 변경 후 invalidateQueries로 캐시 무효화 하면 목록 자동 갱신 가능
  4. Mutation은 수동 실행(예: 버튼 클릭 시)으로 트리거
  5. QueryKey로 통일된 키 사용 → 캐시 충돌 방지 & 유지보수 편리

useQuery – GET (데이터 가져오기)

역할

  • 서버에서 데이터 가져올 때 사용
  • 컴포넌트 로드 시 자동 실행
  • 결과를 자동으로 캐싱(저장) 하고, 리페치(새로고침) 도 편하게 해줌
  • 주로 목록 조회, 상세 조회 같은 읽기 전용 요청에 사용
import { useQuery } from '@tanstack/vue-query'
import axios from 'axios'

const fetchStudents = async () => {
  const { data } = await axios.get('/api/students')
  return data
}

// 쿼리 훅
const { data, isLoading, error } = useQuery({
  queryKey: ['students'],    // 캐싱용 이름표
  queryFn: fetchStudents,    // 실제 데이터 가져오는 함수
  staleTime: 1000 * 60,      // 1분 동안은 신선한 데이터로 취급(지나면 갱신)
})

useMutation - POST, PUT, PATCH (데이터 변경하기)

역할

  • 서버에 데이터를 추가, 수정, 삭제할 때 사용(즉, 데이터에 변경이 일어날 때)
  • 결과를 캐시하지 않는다 → 대신 성공 후 직접 쿼리 무효화(invalidate)나 리페치(refetch) 해줘야 함
  • 주로 폼 제출, 수정 버튼 클릭 같은 동작에 사용
import { useMutation, useQueryClient } from '@tanstack/vue-query'
import axios from 'axios'

const addStudent = async (newStudent: { name: string }) => {
  const { data } = await axios.post('/api/students', newStudent)
  return data
}

// mutation 훅
const queryClient = useQueryClient()

const { mutate, isPending } = useMutation({
  mutationFn: addStudent,          // POST 요청 실행
  onSuccess: () => {
    // 성공하면 students 쿼리 새로고침
    queryClient.invalidateQueries({ queryKey: ['students'] })
  },
})

사용할 때

<button @click="mutate({ name: '홍길동' })">학생 추가</button>

useQuery + useMutation + invalidateQueries 예시

const queryClient = useQueryClient()

const { data: students } = useQuery({ queryKey: ['students'], queryFn: fetchStudents })

const { mutate: addStudent } = useMutation({
  mutationFn: (newStudent) => axios.post('/api/students', newStudent),
  onSuccess: () => {
    // 학생 추가 후 목록 다시 불러오기
    queryClient.invalidateQueries({ queryKey: ['students'] })
  },
})