Отслеживание запросов

RTK Query строит модель данных вокруг концепции запросов как первоклассных сущностей состояния. Каждый запрос в системе — это не просто функция получения данных, а полноценная единица, которая регистрируется в кэше, отслеживается по жизненному циклу и синхронизируется с остальными частями приложения. Механизм отслеживания запросов является ключевым элементом, обеспечивающим автоматическое обновление данных, управление подписками и оптимизацию повторных обращений к серверу.

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

Ключ запроса можно представить в виде:

endpointName + serializedArguments

Например:

getUser(1)
getUser(2)
getPosts({ page: 1, limit: 10 })

Каждый из этих вызовов создаёт отдельную запись в кэше, даже если используется один и тот же endpoint.

Внутренняя структура хранения позволяет RTK Query отслеживать не только сам факт наличия данных, но и их привязку к конкретным компонентам и подписчикам.

Подписки на запросы

Когда компонент использует хук типа useGetUserQuery, он автоматически становится подписчиком на соответствующий запрос. Подписка фиксирует:

  • ключ запроса
  • компонент-потребитель
  • время начала использования данных
  • активность подписки

Подписка создаётся при монтировании компонента и удаляется при размонтировании. Это позволяет RTK Query точно определять, какие данные востребованы в текущий момент.

При появлении нескольких компонентов, использующих один и тот же запрос, RTK Query не выполняет повторный сетевой запрос. Вместо этого все компоненты разделяют одну и ту же подписку на кэшированные данные.

Счётчик активных подписчиков

Каждый запрос внутри кэша содержит счётчик подписчиков. Это значение увеличивается при каждом новом использовании данных и уменьшается при удалении подписки.

Логика работы выглядит следующим образом:

  • первый компонент вызывает запрос → создаётся запись в кэше, счётчик = 1
  • второй компонент использует тот же запрос → счётчик = 2
  • первый компонент размонтируется → счётчик = 1
  • второй компонент размонтируется → счётчик = 0

Когда счётчик достигает нуля, RTK Query запускает механизм возможного удаления данных из кэша, учитывая параметры keepUnusedDataFor.

Управление временем жизни данных

RTK Query не удаляет данные мгновенно после исчезновения подписчиков. Вместо этого используется отложенное удаление.

Параметр:

keepUnusedDataFor: number

задаёт время в секундах, в течение которого данные остаются в кэше после потери последнего подписчика.

Это позволяет:

  • избежать повторных запросов при кратковременном размонтировании компонентов
  • повысить отзывчивость интерфейса
  • уменьшить нагрузку на сеть

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

Активные и неактивные запросы

RTK Query разделяет запросы на активные и неактивные в зависимости от наличия подписчиков.

Активный запрос — имеет хотя бы одного подписчика.

Неактивный запрос — не имеет подписчиков, но может оставаться в кэше до истечения времени keepUnusedDataFor.

Эта классификация влияет на поведение:

  • активные запросы могут автоматически рефетчиться
  • неактивные находятся в режиме ожидания удаления

Автоматическое повторное получение данных

Отслеживание запросов тесно связано с механизмами автоматического обновления данных. RTK Query использует информацию о подписках для определения необходимости повторного запроса.

Автоматический рефетч может происходить при:

  • фокусе окна браузера
  • восстановлении интернет-соединения
  • повторном монтировании компонента
  • истечении интервала refetchOnMountOrArgChange

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

Перекрытие одинаковых запросов

RTK Query оптимизирует ситуацию, когда несколько компонентов одновременно инициируют одинаковые запросы. В этом случае используется механизм дедупликации.

Если запрос с таким ключом уже выполняется:

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

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

Отслеживание состояния запроса

Каждый запрос хранит дополнительную информацию о своём состоянии:

  • status: pending, fulfilled, rejected
  • isFetching: активный сетевой запрос
  • isSuccess: успешное завершение
  • isError: ошибка выполнения
  • startedTimeStamp: время старта запроса

Эти состояния обновляются в зависимости от жизненного цикла запроса и используются для управления UI.

Отслеживание состояния позволяет точно понимать:

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

Инвалидация через отслеживание запросов

Хотя инвалидация чаще ассоциируется с тегами, отслеживание запросов также участвует в этом процессе.

При вызове invalidateTags RTK Query:

  • находит все запросы, связанные с тегами
  • проверяет активные подписки
  • помечает данные как устаревшие
  • при необходимости инициирует повторный запрос

Таким образом, система отслеживания запросов выступает связующим звеном между кэшем и механизмом обновления данных.

Группировка запросов по аргументам

Аргументы запроса сериализуются и используются для точного различения данных. Даже небольшое изменение параметров приводит к созданию новой записи.

Пример различий:

getUsers({ page: 1 })
getUsers({ page: 2 })
getUsers({ page: 1, limit: 10 })

Каждый вариант создаёт отдельную сущность в системе отслеживания.

Это позволяет:

  • хранить независимые страницы данных
  • избегать конфликтов кэша
  • точно контролировать повторное использование результатов

Очистка устаревших запросов

Когда запрос перестаёт быть активным и истекает время хранения, RTK Query удаляет его из кэша.

При этом удаляются:

  • данные ответа
  • метаданные состояния
  • информация о подписках

Очистка выполняется автоматически внутри middleware RTK Query и не требует ручного вмешательства.

Связь с жизненным циклом Redux Store

Отслеживание запросов интегрировано в общий жизненный цикл Redux. Каждый action, связанный с RTK Query, проходит через middleware, где обновляется состояние кэша.

Это обеспечивает:

  • централизованное управление состоянием запросов
  • предсказуемую структуру данных
  • возможность интеграции с DevTools

Каждое изменение подписок фиксируется как событие в store, что делает систему полностью наблюдаемой.

Поведение при повторном монтировании компонентов

Если компонент, использующий запрос, размонтируется и затем снова монтируется:

  • при наличии кэшированных данных запрос не выполняется
  • подписка восстанавливается
  • счётчик подписчиков увеличивается
  • UI мгновенно получает данные без задержки

Если данные были удалены из-за истечения времени хранения, выполняется новый сетевой запрос.

Влияние аргументов skip и polling

Отслеживание запросов учитывает специальные параметры управления:

  • skip отключает создание подписки
  • pollingInterval поддерживает периодические обновления

При skip = true запрос не регистрируется в системе отслеживания, что полностью исключает его из кэширования и подписок.

Polling, напротив, поддерживает активный статус запроса и увеличивает частоту обновлений без участия пользователя.

Согласованность данных между подписчиками

RTK Query гарантирует, что все подписчики одного запроса получают одинаковое состояние данных. Обновление кэша автоматически синхронизируется между всеми компонентами.

Это достигается через:

  • единый источник состояния в Redux store
  • централизованное обновление query slice
  • реактивную систему подписок

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