---
title: 'useQuery의 Query Status와 Fetch Status'
publishedAt: '2026. 01. 07'
description: 'TanStack Query v5 기준 useQuery 응답에서 Query Status와 Fetch Status를 구분하는 핵심 원리를 정리했습니다.'
tags: ['react', 'tanstack query']
---


TanStack Query에서 제공하는 **useQuery()** 훅을 사용해 비동기 데이터를 요청하면,
데이터와 함께 캐싱에 관련된 여러 정보를 응답으로 제공하는 것을 확인할 수 있습니다.

```ts
import { useQuery } from '@tanstack/react-query';

const {
  data,
  dataUpdatedAt,
  error,
  errorUpdatedAt,
  failureCount,
  failureReason,
  fetchStatus,
  isError,
  isFetched,
  isFetchedAfterMount,
  isFetching,
  isInitialLoading,
  isLoading,
  isLoadingError,
  isPaused,
  isPending,
  isPlaceholderData,
  isRefetchError,
  isRefetching,
  isStale,
  isSuccess,
  isEnabled,
  promise,
  refetch,
  status,
  // v5.90.16 기준 data 제외 24개의 추가 정보 필드를 제공합니다.
} = useQuery({
  queryKey,
  queryFn,
  // ...
});
```

이들 정보 중 다수가 `is~`와 같은 Boolean 형태를 가지며, 요청의 특정 상태를 나타내는 플래그처럼 보입니다.
다만, 저의 경우 처음 봤을 때 이름만으로 필요한 플래그를 골라내기 어려웠습니다.

예시로 비동기 데이터를 가져오는 동안 스켈레톤 UI를 보여주려고 했을 때,
`isPending` · `isPaused` · `isLoading` 중 어떤 필드를 사용해야 할지 확실치 않다고 생각했습니다.

## useQuery 상태 필드를 헷갈리기 쉬운 이유

![Reddit "What Differences between Query Status and Fetch Status?"](/posts/query-status-and-fetch-status-in-usequery/reddit-what-differences-between-query-status-and-fetch-status.webp?width=600)

> 저만 헷갈리는 부분은 아닌 듯합니다..! 특히 그러한 이유는…

### 각 버전을 거치며 상태 정의가 꾸준히 변경되어 왔습니다.

TanStack Query는 2025년 12월 기준 Latest인 *v5.90.16*까지 발전하며 ‘요청 상태’에 대한 메이저한 개선 사항을 지속적으로 포함해 왔습니다.
예를 들어 v5에서는 다음 사항들이 변경되었습니다:

- v4의 `status: loading` 상태가 v5에서는 `status: pending`으로 이름이 변경되었습니다.
- v4의 `isInitialLoading` 플래그가 v5에서는 `isLoading`으로 이름이 변경되었습니다.
- v5의 `isLoading` 플래그는 `isPending && isFetching`과 논리적으로 동일합니다.
- _...else_

### 응답 내에 여러 파생 플래그가 존재합니다.

- `status: pending`과 `isPending` 중 어떤 것을 사용해야 하나요?

얼추 예상한 바와 같이, `(status === pending) <-> isPending`이며 `(fetchStatus === fetching) <-> isFetching`입니다.
`status`나 `fetchStatus` Union 타입의 각 값에 `isPending`, `isFetching`과 같은 파생 플래그가 대응하는 구조이기 때문입니다.

이러한 방식은 코드를 작성할 때는 편리하나, 응답 객체를 바라볼 때 한해서 어떤 값을 사용해야 할지 판단하기 어렵게 만드는 요인입니다.

### 독립적인 두 가지 상태 체계가 존재합니다.

TanStack Query는 v4 이후부터 Query Status(`status`)에서 Fetch Status(`fetchStatus`)를 분리하며,
두 가지의 독립적인 상태를 제공하기 시작했습니다.
이를 통해 하나의 상태 플래그만으로는 모호했던 상황을 자연스럽게 표현 가능해졌지만,
앞서 각 상태 플래그가 어떤 의도로 구분되었는지에 대해 이해가 필요합니다.

## 상태 필드

### Query Status

```tsx
const {
  // focus(1:4)
  status,
  isPending,
  isSuccess,
  isError,
} = useQuery({
  queryKey,
  queryFn,
  // ...
});
```

Query Status는 **데이터의 존재 여부**에 대한 상태입니다.
“화면에 보여줄 데이터가 현재 캐시에 존재하는지 _(Do we have any or not?)_ ”에 대한 여부를 표현합니다.

- `status === 'pending'`: 아직 데이터를 받아오지 못한 상태
- `status === 'success'`: 데이터를 성공적으로 받아온 상태
- `status === 'error'`: 데이터를 받아오다 에러가 발생한 상태

각 파생 플래그는 `status` Union 타입의 하나의 값에 대응하므로 상호 배타성을 가집니다.
`isPending`, `isSuccess`, `isError` 중 반드시 하나만 `true`이며, 모두가 `false`인 경우는 존재하지 않습니다.

- `isPending`은 `status === 'pending'`과 동일
- `isSuccess`는 `status === 'success'`와 동일
- `isError`는 `status === 'error'`와 동일

### Fetch Status

```tsx
const {
  // focus(1:3)
  fetchStatus,
  isFetching,
  isPaused,
} = useQuery({
  queryKey,
  queryFn,
  // ...
});
```

Fetch Status는 **쿼리 함수(queryFn)의 현재 실행 중 여부**에 대한 상태입니다.
“지금 데이터를 가져오기 위해 요청 중인지 _(Is it running or not?)_ ”에 초점을 맞추고 있습니다.

- `fetchStatus === 'fetching'`: 쿼리 함수가 실행 중인 상태
- `fetchStatus === 'paused'`: 쿼리 함수가 네트워크 오프라인 등의 이유로 실행 중단된 상태
- `fetchStatus === 'idle'`: 쿼리 함수가 실행 중이지 않은 상태

Query Status와 마찬가지로 `fetchStatus`의 파생 플래그 또한 상호 배타성을 가집니다.
`isFetching`, `isPaused` 중 반드시 하나만 `true`이며,
모두가 `false`인 경우는 반드시 `fetchStatus === 'idle'`를 가리킵니다.

- `isFetching`: `fetchStatus === 'fetching'`과 동일
- `isPaused`: `fetchStatus === 'paused'`와 동일

`isIdle` 플래그는 존재하지 않지만, `isFetching === false && isPaused === false`인 경우로 유추하거나
`fetchStatus === 'idle'`로 직접 확인합니다.

---

- 참고: [Why Two Different States? | TanStack Query React Docs](https://tanstack.com/query/latest/docs/framework/react/guides/queries#why-two-different-states)

Fetch Status는 v4에서부터 처음 도입되었습니다.
이전에는 `status` 하나로 모든 상태를 표현했는데, 예시로 아래와 같은 상황에서 불편함이 존재했습니다.

1. 단일 `loading` 상태가 네트워크가 오프라인인 경우와 느리지만 로딩하고 있는 상태를 구분할 수 없었습니다.
2. 이미 데이터가 존재하며(`success`) 백그라운드에서 데이터를 재요청하는 경우를 판별하기 어려웠습니다.
3. 비활성화된 쿼리(`enabled: false`)와 쿼리가 막 시작된 경우(`idle → loading`)를 구분하기 모호한 구간이 존재했습니다.

기존의 Query Status에서 Fetch Status를 별도로 분리함으로써, 데이터의 상태와 요청의 진행 상태를 독립적으로 추적할 수 있게 되었습니다.

1. 단일 `loading` 상태가 네트워크가 오프라인인 경우와 느리지만 로딩하고 있는 상태를 구분할 수 없었습니다.  
→ **네트워크가 오프라인인 경우를 `fetchStatus: paused`로 명확히 구분할 수 있습니다.**
2. 이미 데이터가 존재하며(`success`) 백그라운드에서 데이터를 재요청하는 경우를 판별하기 어려웠습니다.  
→ **`status: success`면서 `fetchStatus: fetching`인 경우로 표현 가능합니다.**
3. 비활성화된 쿼리(`enabled: false`)와 쿼리가 막 시작된 경우(`idle → loading`)를 구분하기 모호한 구간이 존재했습니다.  
→ **`fetchStatus: idle`한 상태로 명확히 분리했습니다.**

---

### Complex Status

```tsx
const {
  // focus(1:7)
  isFetched,
  isFetchedAfterMount,
  isLoading,
  isInitialLoading,
  isLoadingError,
  isRefetching,
  isRefetchingError,
} = useQuery({
  queryKey,
  queryFn,
  // ...
});
```

- `isFetched`: `status === 'success' || status === 'error'`와 동일
- `isFetchedAfterMount`: 현재 페이지나 컴포넌트가 마운트된 이후에 데이터 요청이 한 번이라도 수행 완료되었는지의 여부

결과가 성공이든 에러든 요청 시도가 한 번이라도 수행 완료되었음을 의미합니다.
화면 진입 시 캐시에 이미 데이터가 있는 경우 바로 `isFetched`는 `true`가 되지만,
요청이 발생하지 않았으므로 `isFetchedAfterMount: false`로 남아있습니다.
이후 재요청이 발생하는 시점에야 `isFetchedAfterMount: true`가 됩니다.
    
- `isLoading`: `isPending && isFetching`과 동일
- `isLoadingError`: `isError && !isFetched`와 동일
- `isInitialLoading`: `isLoading`과 동일 _(deprecated)_
    
`isLoading`은 쿼리 함수의 첫 번째 요청이 진행 중인 상태입니다.
`isLoadingError`는 첫 번째 요청 시도 자체가 실패해서 화면에 보여줄 데이터가 아예 없는 에러 상태를 가리킵니다.

- `isRefetching`: `!isPending && isFetching`과 동일
- `isRefetchingError`: `isError && isFetched`와 동일

백그라운드에서 재요청이 진행 중인 경우 `isRefetching: true`가 됩니다.
`isRefetchingError: true`은 상태는 이미 이전에 성공한 데이터가 있어 화면에는 데이터가 있지만,
백그라운드 재요청 시도가 실패한 상태입니다.

## 상태 전이 시나리오

데이터를 요청하는 과정에서 발생할 수 있는 다양한 시나리오들을 살펴보면,
Query Status와 Fetch Status가 서로 독립적이며 다양한 상황에서 조합되어 나타날 수 있다는 사실을 더 쉽게 이해할 수 있습니다.

### 1-a. 초기화(마운트) 및 첫 데이터를 요청하는 경우

![Case 1-a. Mounted and First Fetching](/posts/query-status-and-fetch-status-in-usequery/case-1-a-mounted-and-first-fetching.webp)

useQuery가 마운트되면 Fetch Status는 `idle`로 초기화되며, 요청을 시작함에 따라 `fetching`으로 전이합니다.
데이터를 가져오기 위한 요청이 실제로 수행되고 있다는 사실을 사용자에게 전달하기 위해 스켈레톤 UI를 사용하기 적절한 상태이며,
`isLoading`을 활용해 더 간결하게 나타낼 수 있습니다.

- 참고: [Important Defaults | TanStack Query React Docs](https://tanstack.com/query/latest/docs/framework/react/guides/important-defaults)

Query Status는 기본적으로 `pending`이지만, `initialData`가 존재하는 경우 초기화될 때부터 `success` 상태입니다.
단, `placeholderData`의 경우는 데이터가 없는 경우와 마찬가지로 `pending` 상태를 가집니다.

### 1-b. 데이터를 요청하지 않고 대기하는 경우

![Case 1-b. Wait Until Enabled True](/posts/query-status-and-fetch-status-in-usequery/case-1-b-wait-until-enabled-true.webp)

만약 useQuery가 마운트되는 시점에 `enabled: false` 옵션이 설정된 경우,
Fetch Status는 `idle` 상태를 유지하며 요청을 수행하지 않습니다.

> `Query` 클래스의 생성자 함수에서 호출되는 `getDefaultState()` 메서드는 내부에서 `idle`을 초깃값으로 가지므로,
`fetchFn()` 호출이 발생하지 않는다면 Fetch Status는 `fetching`으로 전이하지 않고 `idle`로 남아있습니다.

이때는 스켈레톤 UI나 로딩 인디케이터보다도, 필요한 필터 옵션을 입력하거나 사용자에게 권한을 요청하는 등 사용자 액션을 유도하는 것이 적절합니다.

### 2-a. 데이터를 성공적으로 받아온 경우

![Case 2-a. Successed Fetching Data](/posts/query-status-and-fetch-status-in-usequery/case-2-a-successed-fetching-data.webp)

요청에 성공한 경우, 데이터를 화면에 표시하거나 컴포넌트에 전달합니다.
useQuery 실행에서 가장 이상적인 시나리오입니다!

### 2-b. 네트워크 연결이 오프라인인 경우

![Case 2-b. Paused Until Network Conntected](/posts/query-status-and-fetch-status-in-usequery/case-2-b-paused-until-network-conntected.webp)

Fetch Status가 `paused`일 때는 네트워크 상태가 비활성화되어 요청이 중단된 경우입니다.
TanStack Query는 네트워크가 다시 연결되기를 감지할 수 있으므로,
그동안 사용자에게 네트워크 연결을 확인해 달라는 메시지를 표시하도록 할 수 있습니다.

> v3까지는 useQuery가 네트워크가 필요하지 않은 비동기 요청(ex: 무거운 Web Worker 요청 등)을 수행할 때도
네트워크 상태에 따라 해당 요청이 중단되는 문제가 있었습니다.
이제는 v4부터 도입된 [`networkMode`](https://tanstack.com/query/latest/docs/framework/react/guides/network-mode)
옵션을 설정해 이러한 문제를 방지할 수 있습니다.

### 2-c. 에러 발생 시

![Case 2-c. Error Occurred While Fetching](/posts/query-status-and-fetch-status-in-usequery/case-2-c-error-occurred-white-fetching.webp)

- 참고: [Query Retries | TanStack Query React Docs](https://tanstack.com/query/latest/docs/framework/react/guides/query-retries)

useQuery는 요청이 실패한 경우 기본적으로 3번의 재시도를 수행하며,
지수 백오프 전략에 의해 기본 1000ms부터 시작해 2배씩 간격을 늘려 가며 요청을 재시도합니다.

이후에 최종적으로 모든 재시도가 실패한 경우에 `retryer`가 `Promise.reject()`를 호출하므로,
이 시점에 도달해서야 Query Status가 `error`로 전이합니다. 그동안에는 쭉 `pending`으로 남아있습니다.

> `initialData`가 존재하면 요청 자체는 실패해서 `status: error` 상태로 전이될 수 있지만,
`data`는 그대로 남아 UI에 표시될 수 있습니다.
이는 TanStack Query가 _Stale-While-Revalidate_ 전략을 핵심으로 따르고 있기 때문입니다.

### 3. 백그라운드 재요청 시

![Case 3. Background Refetching](/posts/query-status-and-fetch-status-in-usequery/case-3-background-refetching.webp)

이미 화면에 데이터가 표시되고 있는데, 브라우저 포커싱 이벤트 혹은 캐시를 사용하는 다른 컴포넌트의 마운트 등
TanStack Query 자체 메커니즘에 의해 백그라운드에서 새로운 데이터 요청을 시도할 수 있습니다.
이때 데이터가 존재하므로 Query Status는 `success`지만, Fetch Status는 `fetching`이 됩니다.

이 상태에서는 기존의 요청에 성공한 데이터가 존재하므로, 데이터를 가리지 않는 별도의 영역에서 로딩 인디케이터를 표시하는 것이 적절합니다.
재요청에 실패하더라도, 기존의 'Stale'한 데이터를 지속적으로 표시해 사용자 경험에 도움을 줄 수 있습니다.

```tsx
// focus(1:2)
// 데이터가 없을 때만 전체 에러 화면을 표시
if (isError && !data) {
  return <div>요청 중 에러가 발생했습니다: {error.message}</div>;
}

return (
  // focus(2:3)
  <div>
    {/* 백그라운드 요청 중 에러 발생 시, 데이터와 별개의 영역에서 표시 */}
    {isError && <div>업데이트 중 에러가 발생했습니다...</div>}
    <ul>
      {data.map(todo => (
        <li key={todo.id}>{todo.title}</li>
      ))}
    </ul>
  </div>
);
```

## 추가: useQuery 내부 상태 머신과 파생 플래그

> "(번역) React Query의 장점 중 하나는 쿼리의 상태 필드에 쉽게 접근할 수 있다는 것입니다.
이를 통해 쿼리가 로딩 중인지, 아니면 에러가 발생했는지를 즉각적으로 알 수 있습니다.
라이브러리는 이를 위해 **내부 상태 머신**에서 파생된 여러 Boolean 플래그를 노출합니다.  
…  
여기서 주의할 점은 **`isFetching` 플래그는 내부 상태 머신의 일부가 아니라는 것**입니다.
이 플래그는 요청이 진행 중(’in-flight’)일 때마다 true가 되는 추가적인 상태입니다.
따라서 'fetching이면서 success'일 수 있고, 'fetching이면서 error'일 수도 있습니다.
하지만 **'loading(pending)이면서 동시에 success'일 수는 없습니다.** 상태 머신이 이를 확실히 보장하기 때문입니다."<br />  
― TkDodo, 「Status Checks in React Query」

공식 문서는 `status`와 같은 값은 내부 상태 머신에 의해 제어되고 있다고 언급하며,
`isSuccess`와 같은 플래그는 상태 머신의 일부가 아니라고 설명하고 있습니다.
이는 `@tanstack/react-query`의 핵심 로직이 정의된 `@tanstack/query-core` 패키지를 살펴보면 자세히 확인할 수 있습니다.

```ts
// @tanstack/query-core/src/types.ts
// ...

export type QueryStatus = 'pending' | 'error' | 'success'
export type FetchStatus = 'fetching' | 'paused' | 'idle'
```

```tsx
// @tanstack/query-core/src/query.ts
// ...

import type {
  // ...
  FetchStatus,
  QueryStatus,
} from './types';

export interface QueryState<TData = unknown, TError = DefaultError> {
  data: TData | undefined;
  dataUpdateCount: number;
  dataUpdatedAt: number;
  error: TError | null;
  errorUpdateCount: number;
  errorUpdatedAt: number;
  fetchFailureCount: number;
  fetchFailureReason: TError | null;
  fetchMeta: FetchMeta | null;
  isInvalidated: boolean;
  // focus(1:2)
  status: QueryStatus;
  fetchStatus: FetchStatus;
}
```

useQuery 내부의 `QueryState`를 살펴보면, `status`와 `fetchStatus`는 타입스크립트의 Discriminated Union 타입으로 정의되어 있습니다.
따라서 아래와 같은 상태 머신의 특성을 가지게 됩니다.

- 유한한(finite): 가능한 모든 유한 상태가 명시적으로 정의되어 있어, 예상치 못한 상태로의 전이가 발생하지 않습니다.
- 결정론적(deterministic): `status`는 `'pending' | 'error' | 'success'` 중 정확히 하나의 값만 가질 수 있습니다.
동시에 두 가지 상태가 될 수 없으므로, `isPending && isSuccess`와 같은 조합이 실제로 발생하지 않음을 보장합니다.

반면, useQuery의 반환 값이 계산되는 `QueryObserver.createResult()` 메서드를 살펴보면
`isPending`, `isSuccess` 등의 Boolean 플래그들은 상태 머신 자체를 구성하는 요소라기보다,
`status`와 `fetchStatus`의 값을 기반으로 매번 새롭게 계산되어 제공되는 편의성 플래그임을 확인할 수 있습니다.

```ts
// @tanstack/query-core/src/queryObserver.ts

export class QueryObserver<
  TQueryFnData = unknown,
  TError = DefaultError,
  TData = TQueryFnData,
  TQueryData = TQueryFnData,
  TQueryKey extends QueryKey = QueryKey,
> extends Subscribable<QueryObserverListener<TData, TError>> {
  // ...
	
  protected createResult(
    //...

    // focus(1:3)
    const isFetching = newState.fetchStatus === 'fetching'
    const isPending = status === 'pending'
    const isError = status === 'error'

    // focus(1:1)
    const isLoading = isPending && isFetching
    const hasData = data !== undefined

    const result: QueryObserverBaseResult<TData, TError> = {
      status,
      fetchStatus: newState.fetchStatus,
      // focus(1:5)
      isPending,
      isSuccess: status === 'success',
      isError,
      isInitialLoading: isLoading,
      isLoading,
      data,
      dataUpdatedAt: newState.dataUpdatedAt,
      error,
      errorUpdatedAt,
      failureCount: newState.fetchFailureCount,
      failureReason: newState.fetchFailureReason,
      errorUpdateCount: newState.errorUpdateCount,
      // focus(1:11)
      isFetched: newState.dataUpdateCount > 0 || newState.errorUpdateCount > 0,
      isFetchedAfterMount:
        newState.dataUpdateCount > queryInitialState.dataUpdateCount ||
        newState.errorUpdateCount > queryInitialState.errorUpdateCount,
      isFetching,
      isRefetching: isFetching && !isPending,
      isLoadingError: isError && !hasData,
      isPaused: newState.fetchStatus === 'paused',
      isPlaceholderData,
      isRefetchError: isError && hasData,
      isStale: isStale(query, options),
      refetch: this.refetch,
    }

    return result as QueryObserverResult<TData, TError>
  }
  
  // ...
}
```

- 참고: [TypeScript | TanStack Query React Docs](https://tanstack.com/query/latest/docs/framework/react/typescript)

추가로, 타입스크립트 4.6버전 이후로 타입 추론 지원이 강화되어 `status`와 같은 파생 플래그를 수행한 경우도
타입 좁히기를 수행할 뿐만 아니라, `isLoading && isError`와 같은 논리적으로 가능하지 않은 구문 또한
`never` 타입으로 분류해 *“Unreachable code detected”* 경고를 표시합니다.

```ts
const { data, isSuccess, isError } = useQuery({
  queryKey: ['test'],
  queryFn: () => Promise.resolve(5),
})

if (isSuccess) {
  data
  //  ^? const data: number
}

if (isSuccess && isError) {
  // Property '...' does not exist on type 'never'
}
```

## 버전 별 주요 변경사항

![Comparison of useQuery Ststus Changes](/posts/query-status-and-fetch-status-in-usequery/comparison-of-usequery-status-changes.webp)

### v3 → v4

v3에서는 `status` 하나로 모든 쿼리 상태를 관리했으며, `idle` · `loading` · `error` · `success`의 네 가지 상태가 존재했습니다.
Fetch Status는 명시적으로 구분되지 않았으며, 대신에 `isFetching` 플래그를 통해 실제 요청 진행 여부를 확인할 수 있었습니다.

v4로 넘어오며 `status`에서 `idle`이 제거되고 `loading` · `error` · `success` 세 가지만 남았으며,
`fetchStatus`라는 새로운 상태 필드가 도입되어 기존의 `status`와 함께 이중 상태 체계가 확립되었습니다.
새로 추가된 `fetchStatus`는 `fetching` · `paused` · `idle`로 구성되어 실제 요청 진행 상태를 별도로 추적하게 되었습니다.

또한 `isInitialLoading` 플래그가 추가되어 `status === 'loading' && fetchStatus === 'fetching'`인
'진짜 첫 로딩' 상태를 쉽게 판별할 수 있게 되었습니다.

### v4 → v5

v5로 넘어오며 TanStack Query 개발팀은 ‘loading’ 상태가 가지는 모호함을 해소하고자,
`status`의 `loading`을 `pending`으로 변경해 "데이터가 아직 준비되지 않은 대기 상태"라는 의미를 더 명확히 전달했습니다.

이에 맞춰 파생 플래그들도 재정의되었는데, `isLoading`이 `isPending`으로 바뀌었고
기존 v4의 `isInitialLoading`이 새롭게 `isLoading`로 불리도록 변경되었습니다.

## 결론

- useQuery의 상태 필드가 헷갈리는 이유는, 버전업 과정에서 실제로 많은 부분이 변경되었기 때문입니다.
- 여러 모호한 시나리오(네트워크 중단, 백그라운드 요청 등)를 명확히 분리해 표현하기 위해 Query Status는 ‘데이터의 존재 여부’에,
Fetch Status는 ‘요청 수행 상태’에 초점을 맞추고 있으며 두 상태 필드는 독립적인 관계를 가집니다.
- 과거에는 타입스크립트 사용 시, 파생 플래그(ex: `isFetching`) 대신 상태를 나타내는 Union 값(ex: `fetchStatus`)을 활용하는 편이 권유되었으나,
최신 버전의 타입스크립트에서는 파생 플래그에 대한 타입 추론 또한 잘 이루어지고 있습니다.
- TanStack Query가 v5에 이르기까지 상태 필드에 대해 어떤 메이저한 변경 사항들이 있었는지를 인지한다면,
다양한 버전을 배경으로 작성된 문서들을 참고하며 혼동이 오는 것을 방지할 수 있다고 생각합니다.

## 참고

- [useQuery | TanStack Query React Docs](https://tanstack.com/query/latest/docs/framework/react/reference/useQuery)
- [Status Checks in React Query | TkDodo's blog](https://tkdodo.eu/blog/status-checks-in-react-query)
- [React Query의 구조와 useQuery 실행 흐름 살펴보기 | 함성준님@Kakao ENT. 테크 블로그](https://tech.kakaoent.com/front-end/2023/230720-react-query/)
