Просмотр состояния запросов

TanStack Query рассматривает каждый запрос как объект с четко определённым жизненным циклом. Вместо ручного управления флагами загрузки, ошибок и кэширования библиотека предоставляет унифицированную модель состояния, которая описывает текущее положение запроса в системе: от момента инициализации до получения данных, повторных фетчей и инвалидирования.

Основная идея заключается в том, что состояние запроса разделено на две независимые оси: status и fetchStatus. Первая отражает результат выполнения, вторая — текущее поведение сети.


Основные статусы запроса (status)

Поле status описывает логическое состояние данных:

idle

Запрос ещё не был запущен. В TanStack Query это встречается редко в типичных сценариях useQuery, но может появляться при условных запросах (enabled: false).

pending

Запрос выполняется, данные ещё не получены. В ранних версиях это состояние называлось loading, но в современных версиях используется более точная модель.

success

Запрос завершился успешно, данные получены и сохранены в кэше.

error

Запрос завершился ошибкой. В состоянии доступны объект ошибки и предыдущие данные (если они были закэшированы).


Сетевой статус (fetchStatus)

В отличие от status, поле fetchStatus отражает не результат, а текущее состояние сетевой операции:

fetching

Запрос активно выполняется в данный момент.

paused

Запрос приостановлен. Такое возможно при отсутствии сети, использовании оффлайн-режимов или глобальных конфигураций повторных попыток.

idle

Запрос не выполняет сетевых операций в данный момент.


Разница между status и fetchStatus

Ключевой момент архитектуры TanStack Query заключается в том, что наличие данных и состояние сети — разные вещи.

status отвечает на вопрос: «Есть ли у нас валидный результат?»

fetchStatus отвечает на вопрос: «Что происходит с сетью прямо сейчас?»

Пример комбинаций:

  • status: success, fetchStatus: idle — данные загружены, запрос не активен
  • status: success, fetchStatus: fetching — происходит фоновое обновление (background refetch)
  • status: error, fetchStatus: idle — последняя попытка завершилась ошибкой, новых запросов нет
  • status: pending, fetchStatus: fetching — первичная загрузка

Удобные производные флаги

TanStack Query предоставляет набор вычисляемых флагов, которые упрощают работу с состоянием.

isLoading

Истинно, когда запрос впервые загружается и данных ещё нет.

Эквивалентно:

  • status === "pending"
  • и отсутствуют закэшированные данные

isFetching

Истинно, когда выполняется любой сетевой запрос, независимо от наличия данных.

Это ключевое отличие от isLoading: isFetching может быть true даже при уже отображённых данных.

Пример:

  • пользователь уже видит список
  • происходит фоновое обновление
  • isFetching === true, но UI не обязан блокироваться

isError

Упрощённый доступ к состоянию ошибки.

Эквивалент:

  • status === "error"

isSuccess

Эквивалент:

  • status === "success"

isInitialLoading

Комбинированное состояние, означающее первую загрузку без данных.

Используется для отображения скелетонов интерфейса.


Доступ к данным и ошибкам

data

Поле data содержит результат успешного запроса. Важно учитывать, что:

  • при status: pending data может быть undefined
  • при повторных запросах данные остаются доступными
  • кэш может возвращать устаревшие значения

error

При status: error здесь находится объект ошибки. Часто это:

  • HTTP-ошибка
  • ошибка парсинга
  • кастомная ошибка из queryFn

Stale-состояние и актуальность данных

Отдельно от статусов существует концепция staleTime и логика устаревания данных.

Данные могут находиться в состоянии:

  • свежие (fresh)
  • устаревшие (stale)

Это влияет на автоматический рефетч при:

  • фокусе окна
  • повторном монтировании компонента
  • сетевых восстановлений

Хотя isStale напрямую не является основным флагом useQuery, он проявляется через поведение кэша и автоматические обновления.


Практическая интерпретация состояния

Первичная загрузка

Сценарий:

  • запрос только запущен
  • данных нет

Состояние:

  • status: pending
  • fetchStatus: fetching
  • isLoading: true

UI-логика:

  • отображение скелетона или загрузочного экрана

Данные загружены

Сценарий:

  • запрос завершён успешно
  • данные в кэше

Состояние:

  • status: success
  • fetchStatus: idle
  • isLoading: false

UI-логика:

  • отображение данных

Фоновое обновление

Сценарий:

  • данные уже есть
  • происходит refetch

Состояние:

  • status: success
  • fetchStatus: fetching
  • isFetching: true

UI-логика:

  • данные остаются на экране
  • возможен индикатор обновления без блокировки интерфейса

Ошибка после успешных данных

Сценарий:

  • ранее данные были получены
  • новая попытка завершилась ошибкой

Состояние:

  • status: error
  • fetchStatus: idle
  • error содержит причину
  • data может сохранять старое значение

UI-логика:

  • можно показать ошибку, сохранив старый UI

Поведение при включённом кэше

Кэширование влияет на то, какие состояния будут наблюдаться:

  • повторный вход в компонент не вызывает isLoading
  • данные мгновенно берутся из cache
  • isFetching используется для обновлений в фоне

Ключевая особенность: TanStack Query всегда предпочитает показывать устаревшие данные, чем пустой экран.


Состояния при условных запросах

При использовании enabled: false:

  • запрос не выполняется
  • status часто остаётся idle
  • fetchStatus = idle

После включения:

  • происходит переход в pending
  • запускается обычный жизненный цикл

Влияние retry и refetch

Повторные попытки (retry) не меняют базовую модель статусов, но влияют на fetchStatus:

  • при каждой попытке fetchStatus: fetching
  • при ожидании retry возможен paused или промежуточные состояния

Роль DevTools в наблюдении состояния

Хотя состояние доступно через useQuery, визуальный анализ становится проще через инструменты разработчика TanStack Query Devtools:

  • отображение всех query keys
  • текущий status и fetchStatus
  • история изменений
  • состояние кэша и времени устаревания

Это позволяет точно понимать поведение системы в сложных сценариях с несколькими запросами.


Типичные ошибки интерпретации состояния

Использование isLoading вместо isFetching

Распространённая ошибка — блокировка интерфейса при каждом refetch. isLoading предназначен только для первой загрузки.


Игнорирование fetchStatus

Некорректно считать, что status: success означает отсутствие активности. Фоновый запрос может выполняться параллельно.


Перезапись UI при error без проверки наличия data

TanStack Query допускает ситуацию, когда:

  • есть данные
  • есть ошибка последнего запроса

Игнорирование data в этом случае приводит к потере UX-устойчивости.


Модель состояния как конечный автомат

Поведение запроса можно формализовать как конечный автомат:

  • idle → pending → success / error
  • success → fetching (refetch) → success / error
  • error → fetching → success / error

fetchStatus при этом изменяется ортогонально, не нарушая основной логики переходов.


Композиция состояний в реальных интерфейсах

В сложных интерфейсах состояние запроса редко используется напрямую. Обычно оно преобразуется в UI-модель:

  • skeleton state
  • data state
  • refreshing state
  • error state с fallback data

TanStack Query предоставляет базовые сигналы, но конечная композиция всегда зависит от логики отображения и приоритетов данных.