| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | ||||
| 4 | 5 | 6 | 7 | 8 | 9 | 10 |
| 11 | 12 | 13 | 14 | 15 | 16 | 17 |
| 18 | 19 | 20 | 21 | 22 | 23 | 24 |
| 25 | 26 | 27 | 28 | 29 | 30 | 31 |
- Kotlin If
- 파이썬 반복문
- Kotlin else if
- Kotlin 클래스 속성정의
- Python
- 자바 기본타입
- python Django
- 파이썬 클래스
- 클래스 속성
- Kotlin 클래스
- 파이썬 제어문
- 희망
- Python Class
- 파이썬 장고
- 다중조건문
- 장고 가상환경
- Kotlin 조건문
- 넥스트js
- django virtualenv
- 강제 타입변환
- 성공
- NextJs
- 좋은글
- github
- Variable declaration
- git
- 도전
- Kotlin Class
- 파이썬
- activate 오류
- Today
- Total
키모스토리
TanStack Query (react-query) - #1 (useQuery, 조회) 본문
TanStack Query(이전 명칭: React Query)는 웹 애플리케이션에서 서버 상태를 가져오고, 캐싱하고, 동기화하고, 업데이트하는 작업을 매우 간편하게 만들어 줍니다.
클라이언트 상태 (Client State)
- 사용자 인터페이스(ui)와 관련 된 상태
- (e.g. 모달의 오픈여부, 언어, 테마 등)
- useState 훅을 주로 사
- 서버에서 일어나는 일과 관련 없음.
- 주로 유저 액션에 의해 변경, 클라이언트 내부에서만 관리되고 업데이트 됨
서버상태 (Server State)
- 서버에 저장되지만 클라이언트에 노출하는데 필요한 데이터 (e.g. DB의 상품정보)
- 서버 => 클라이언트로 전송(GET)
- 클라이언트 => 서버로 전송 (POST, PUT, DELETE)
주요 기능
간편한 데이터 fetching
훅 이용, 데이터를 쉽게 가져올 수 있음
자동캐싱
한번 가져온 데이터는 캐시에 저장되고, 동일한 요청이 반복되면 데이터를 재사용하여 네트워크 요청을 줄임
동기화, 백그라운드 업데이트
데이터가 오래되었거나, 다시 필요할때 자동으로 백그라운드에서 데이터를 갱신
Optimistic Update (낙관적 업데이트)
서버 응다전에 UI를 먼저 업데이트해서 좋은 UX를 제공
성공, 애러, 로딩 상태관리
성공, 에러, 로딩 상태를 쉽게 구분해서 처리할 수 있음
예제 프로젝트 생성 (Vite+React)
npm create vite@latest react-query-tutorial -- --template react-ts
cd react-query-tutorial
npm install
npm run dev
react-query 설치
npm i @tanstack/react-query
App.tsx 수정 (react-query를 사용할 수 있도록 Provider 적용)
import "./App.css";
import TodoList from "./TodoList";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
function App() {
// Create a client for React Query
const queryClient = new QueryClient();
return (
<QueryClientProvider client={queryClient}>
<TodoList />
</QueryClientProvider>
);
}
export default App;
TodoList.tsx
import { useQuery } from "@tanstack/react-query";
export default function TodoListPage() {
const { data, isPending, isFetching, isError, error, refetch } = useQuery({
queryKey: ["todoList"], // 각 쿼리를 식별하는 고유 키
queryFn: async () => {
// 쿼리 함수 정의
// 1초 지연 시뮬레이션
await new Promise((resolve) => setTimeout(resolve, 1000));
// Fetch todo items from an API or other source
const response = await fetch(
"https://jsonplaceholder.typicode222.com/todos",
);
return await response.json();
},
retry: 3, // 실패 시 재시도 횟수 false => 재시도 안함
retryDelay: 1000, // 재시도 간격 (밀리초)
});
console.log("isPending:", isPending);
console.log("isFetching:", isFetching);
// 에러 상태 처리
if (isError) {
return <span>애러발생: {error.message}</span>;
}
return (
<div>
<h1>Todo List</h1>
<p>isPending: {isPending ? "Pending..." : "완료"}</p>
<p>isFetching: {isFetching ? "Fetching..." : "완료"}</p>
<button onClick={() => refetch()}>Refetch Todo List</button>
{/* Todo list 결과 data 표시 */}
<ul>
{data?.map((todo: any) => (
<li key={todo.id}>{todo.title}</li>
))}
</ul>
</div>
);
}
결과 객체에는 생산성을 높이기 위해 알아야 할 몇 가지 매우 중요한 상태가 포함되어 있습니다.
쿼리는 특정 시점에 다음 상태 중 하나에만 있을 수 있습니다 .
- isPending 또는 status === 'pending' - 데이터가 존재하는지 여부, 데이터가 아직 없어서 기다리고 있는 상태
- isFetching - 데이터 요청이 진행중인지? 새로운 요청이 활성화 되어 있으면 true
- isError 또는 status === 'error' - 쿼리 중에 오류가 발생했습니다.
- isSuccess 또는 status === 'success' - 쿼리가 성공적으로 완료되었으며 데이터를 사용할 수 있습니다.
이러한 주요 상태 외에도, 쿼리 상태에 따라 더 많은 정보를 확인할 수 있습니다.
- 오류 - 쿼리가 isError 상태인 경우, error 속성을 통해 오류를 확인할 수 있습니다 .
- 데이터 - 쿼리가 isSuccess 상태인 경우, data 속성을 통해 데이터를 사용할 수 있습니다 .
- isFetching - 어떤 상태에서든, 쿼리가 언제든지 (백그라운드 재가져오기를 포함하여) 데이터를 가져오는 중이면 isFetching은 true 가 됩니다 .
대부분의 쿼리 에서는 먼저 isPending 상태를 확인하고, 그 다음 isError 상태를 확인한 후, 마지막으로 데이터가 사용 가능하다고 판단하여 성공 상태를 표시하는 것으로 충분합니다 .
retry - fetch 실패시 재시도 횟수 (false or 0 ~ 재시도 횟수)
retryDelay : 재시도 간격 (ms)
기타 useQuery 옵션
import { useQuery } from "@tanstack/react-query";
import { useState } from "react";
export default function TodoListPage() {
// 쿼리사용여부 state
const [isEnabledQuery, setIsEnabledQuery] = useState(false);
const { data, isPending, isFetching, isError, error, refetch } = useQuery({
queryKey: ["todoList"], // 각 쿼리를 식별하는 고유 키
queryFn: async () => {
// 쿼리 함수 정의
// 1초 지연 시뮬레이션
await new Promise((resolve) => setTimeout(resolve, 1000));
// Fetch todo items from an API or other source
const response = await fetch(
"https://jsonplaceholder.typicode.com/todos",
);
return await response.json();
},
retry: 0, // 실패 시 재시도 횟수 false => 재시도 안함
retryDelay: 1000, // 재시도 간격 (밀리초)
enabled: isEnabledQuery, // 쿼리 활성화 여부
refetchInterval : 3000, // 자동 새로고침 주기설정
staleTime: 5000, // 데이터가 최신 상태로 간주되는 시간 (밀리초) (기본값: 0)
gcTime: 10000, // 가비지 컬렉션 시간 (밀리초) (기본값: 5분)
});
console.log("isPending:", isPending);
console.log("isFetching:", isFetching);
// 에러 상태 처리
if (isError) {
return <span>애러발생: {error.message}</span>;
}
return (
<div>
<h1>Todo List</h1>
<p>isPending: {isPending ? "Pending..." : "완료"}</p>
<p>isFetching: {isFetching ? "Fetching..." : "완료"}</p>
<button onClick={() => setIsEnabledQuery(true)}>리스트보기</button>
<button onClick={() => refetch()}>Refetch Todo List</button>
{/* Todo list 결과 data 표시 */}
<ul>
{data?.map((todo: any) => (
<li key={todo.id}>{todo.title}</li>
))}
</ul>
</div>
);
}
- enabled : true | false, - react query 실행여부 (ex: 초기 페이지 호출시 조회안함, 데이터 요청 버튼 클릭시 조회실행)
- refetchInterval : 3000, - 자동 리패칭 주기 설정 가능 (자동새로고침 기능에 사용)
- refetchOnWindowFocus: true | false - 창에 다시 포커스 될때 패치를 다시 실행 (기본값이 true 이기 때문에 불필요한 요청을 줄여 주고 싶을때 false를 지정해줌)
- staleTime: 5000, 데이터가 신선한지 아닌지관리, 데이터가 신선하다고 간주되는 시간(ms), fresh한 데이터는 네트워크 요청없이 캐시 된 데이터를 재사용
- gcTime : 10000, 메모리에 남아 있을지 삭제할지를 관리, 데이터가캐시에서 삭제되기까지 걸리는 시간 (ms)
staleTime을 길게 잡는 경우
- 변경이 드문 데이터(예: 코드목록, 설정값 등)
- 네트워크 트래픽을 줄이고 싶을때
staleTime을 짧게 잡는 경우
- 실시간성이 중요한 데이터(예: 주식, 알림 등)
- 항상 초신 데이터가 필요할 때
gcTime을 길게 잡는 경우
- 자주 재사용되는 데이터
- 화면 전환이 많고, 빠른 렌더링이 중요한 경우
- staleTime과 동일하거나 더 길게 설정하는 것이 일반적
gcTime을 짧게 잡는 경우
- 메모리 사용을 최소화 하고 싶을때
- 불필요한 데이터가 메모리에 오래 남지 않게 하고 싶을때
ESlint Plugin Query
npm i -D @tanstack/eslint-plugin-query
eslint.config.js
import js from "@eslint/js";
import globals from "globals";
import reactHooks from "eslint-plugin-react-hooks";
import reactRefresh from "eslint-plugin-react-refresh";
import tseslint from "typescript-eslint";
import { defineConfig, globalIgnores } from "eslint/config";
import pluginQuery from "@tanstack/eslint-plugin-query"; // 추가
export default defineConfig([
...pluginQuery.configs["flat/recommended"], // 추가
globalIgnores(["dist"]),
{
files: ["**/*.{ts,tsx}"],
extends: [
js.configs.recommended,
tseslint.configs.recommended,
reactHooks.configs.flat.recommended,
reactRefresh.configs.vite,
],
languageOptions: {
ecmaVersion: 2020,
globals: globals.browser,
},
},
]);
Devtools
npm i @tanstack/react-query-devtools
devtools 활성화 코드 삽입
import { ReactQueryDevtools } from '@tanstack/react-query-devtools'
function App() {
return (
<QueryClientProvider client={queryClient}>
{/* The rest of your application */}
<ReactQueryDevtools initialIsOpen={false} />
</QueryClientProvider>
)
}
아래와 같이 브라우저에서 React Query 의 동작상태 등을 보기 쉽게 확인이 가능함.

'Web Devlopment > NextJs' 카테고리의 다른 글
| Zustand (0) | 2026.01.18 |
|---|---|
| TanStack Query (react-query) - #2 (useMutation, 등록/수정/삭제) (0) | 2026.01.18 |
| Next.js Server Actions: <form action>로 CRUD 만들기 (메모리 DB 예시) (0) | 2026.01.17 |
| #37. Next.js 16 + Prisma 7 + SQLite 회원관리 예제 (0) | 2026.01.02 |
| #36. form action(Server Actions) vs onSubmit(Client Handler) (0) | 2026.01.01 |
