
React 앱에서 API로 데이터를 불러오려면 보통 axios나 fetch를 쓴다.
근데 그 이후가 문제다.
이런 것까지 전부 직접 짜야 한다면?
지옥이다.
그래서 등장한 게 바로 TanStack Query다.
서버에서 불러온 데이터를, 자동으로 캐싱하고, 리패칭하고, 로딩·에러 상태까지 관리해주는 라이브러리다.
옛날 이름은 React Query였고, 지금은 범용화되어 TanStack Query라는 이름으로 바뀌었다.
그래도 우리는 주로 React + TanStack Query 조합으로 사용하게 된다.
맞다. 근데 약간 다르다.
우리가 흔히 아는 Redux나 Zustand 같은 건 클라이언트 상태를 관리하는 도구고,
TanStack Query는 서버 상태(server state)를 전문적으로 다룬다.
| 구분 | 클라이언트 상태 | 서버 상태 |
|---|---|---|
| 예시 | 모달 열림 여부, 토글 상태 | 게시판 글 목록, 유저 정보 |
| 소스 | UI 이벤트, 사용자 입력 | API, DB 등 외부 |
| 변화 | 우리가 직접 바꿈 | 서버에서 바뀜 |
| 관리 도구 | useState, Redux, Zustand 등 | ✅ TanStack Query |
GET 요청을 자주 하거나 여러 컴포넌트에서 공유할 때TanStack Query는 "데이터를 어떻게 관리할까"에 집중한다.
"실제로 데이터를 어떻게 가져오지?"는 나의 선택이다.
그래서 많은 개발자들이 여전히
axios와 함께 사용한다.
| 라이브러리 | 하는 일 |
|---|---|
| axios | 실제 HTTP 요청 (GET, POST 등) |
| TanStack Query | 데이터 상태 관리 (로딩, 에러, 캐싱 등) |
npm install @tanstack/react-query axios
// main.tsx 또는 index.tsx
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
const queryClient = new QueryClient()
<QueryClientProvider client={queryClient}>
<App />
</QueryClientProvider>
import { useQuery } from '@tanstack/react-query'
import axios from 'axios'
const fetchTodos = async () => {
const res = await axios.get('url')
return res.data
}
function TodoList() {
const { data, isLoading, error } = useQuery({
queryKey: ['todos'],
queryFn: fetchTodos,
})
if (isLoading) return <p>로딩 중...</p>
if (error) return <p>에러 발생!</p>
return (
<ul>
{data.map((todo) => (
<li key={todo.id}>{todo.title}</li>
))}
</ul>
)
}
import { useMutation, useQueryClient } from '@tanstack/react-query'
const postTodo = (todo) =>
axios.post('url', todo)
function AddTodoButton() {
const queryClient = useQueryClient()
const mutation = useMutation({
mutationFn: postTodo,
onSuccess: () => {
// 리스트를 다시 불러오기
queryClient.invalidateQueries({ queryKey: ['todos'] })
},
})
return (
<button
onClick={() => mutation.mutate({ title: '새 할 일', completed: false })}
>
할 일 추가
</button>
)
}
useQuery({
queryKey: ['todos', page],
queryFn: () => axios.get(`/todos?page=${page}`).then((res) => res.data),
staleTime: 1000 * 60, // 1분 동안 fresh 처리
refetchOnWindowFocus: false, // 창 다시 포커스 시 재요청 안함
enabled: !!page, // page 값이 있을 때만 실행
})
| 항목 | 설명 |
|---|---|
| 언제 쓰나? | 서버 데이터를 자주 불러오거나, 공유/갱신해야 할 때 |
| axios는? | 실제 HTTP 요청을 담당 (필수는 아님) |
| 함께 쓰는 이유 | 역할이 다름 – axios는 요청, Query는 흐름 관리 |
| 장점 | 캐싱, 로딩/에러 상태 자동 처리, 코드 간결함 |
저도 이거 잘써보고 싶어요...