RTK Query строит модель данных вокруг концепции запросов как первоклассных сущностей состояния. Каждый запрос в системе — это не просто функция получения данных, а полноценная единица, которая регистрируется в кэше, отслеживается по жизненному циклу и синхронизируется с остальными частями приложения. Механизм отслеживания запросов является ключевым элементом, обеспечивающим автоматическое обновление данных, управление подписками и оптимизацию повторных обращений к серверу.
Каждый запрос в RTK Query идентифицируется через комбинацию двух ключевых параметров: имени эндпоинта и аргументов запроса. Эта комбинация формирует уникальный ключ, который используется внутри кэша.
Ключ запроса можно представить в виде:
endpointName + serializedArguments
Например:
getUser(1)
getUser(2)
getPosts({ page: 1, limit: 10 })
Каждый из этих вызовов создаёт отдельную запись в кэше, даже если используется один и тот же endpoint.
Внутренняя структура хранения позволяет RTK Query отслеживать не только сам факт наличия данных, но и их привязку к конкретным компонентам и подписчикам.
Когда компонент использует хук типа useGetUserQuery, он
автоматически становится подписчиком на соответствующий запрос. Подписка
фиксирует:
Подписка создаётся при монтировании компонента и удаляется при размонтировании. Это позволяет RTK Query точно определять, какие данные востребованы в текущий момент.
При появлении нескольких компонентов, использующих один и тот же запрос, RTK Query не выполняет повторный сетевой запрос. Вместо этого все компоненты разделяют одну и ту же подписку на кэшированные данные.
Каждый запрос внутри кэша содержит счётчик подписчиков. Это значение увеличивается при каждом новом использовании данных и уменьшается при удалении подписки.
Логика работы выглядит следующим образом:
Когда счётчик достигает нуля, RTK Query запускает механизм возможного
удаления данных из кэша, учитывая параметры
keepUnusedDataFor.
RTK Query не удаляет данные мгновенно после исчезновения подписчиков. Вместо этого используется отложенное удаление.
Параметр:
keepUnusedDataFor: number
задаёт время в секундах, в течение которого данные остаются в кэше после потери последнего подписчика.
Это позволяет:
Если в течение этого времени появляется новый подписчик, данные повторно используются без запроса к серверу.
RTK Query разделяет запросы на активные и неактивные в зависимости от наличия подписчиков.
Активный запрос — имеет хотя бы одного подписчика.
Неактивный запрос — не имеет подписчиков, но может
оставаться в кэше до истечения времени
keepUnusedDataFor.
Эта классификация влияет на поведение:
Отслеживание запросов тесно связано с механизмами автоматического обновления данных. RTK Query использует информацию о подписках для определения необходимости повторного запроса.
Автоматический рефетч может происходить при:
refetchOnMountOrArgChangeВажно, что рефетч выполняется только для активных запросов, имеющих подписчиков. Это предотвращает ненужные сетевые операции.
RTK Query оптимизирует ситуацию, когда несколько компонентов одновременно инициируют одинаковые запросы. В этом случае используется механизм дедупликации.
Если запрос с таким ключом уже выполняется:
Это исключает проблему дублирования сетевых вызовов при массовом рендеринге компонентов.
Каждый запрос хранит дополнительную информацию о своём состоянии:
status: pending, fulfilled,
rejectedisFetching: активный сетевой запросisSuccess: успешное завершениеisError: ошибка выполненияstartedTimeStamp: время старта запросаЭти состояния обновляются в зависимости от жизненного цикла запроса и используются для управления UI.
Отслеживание состояния позволяет точно понимать:
Хотя инвалидация чаще ассоциируется с тегами, отслеживание запросов также участвует в этом процессе.
При вызове invalidateTags RTK Query:
Таким образом, система отслеживания запросов выступает связующим звеном между кэшем и механизмом обновления данных.
Аргументы запроса сериализуются и используются для точного различения данных. Даже небольшое изменение параметров приводит к созданию новой записи.
Пример различий:
getUsers({ page: 1 })
getUsers({ page: 2 })
getUsers({ page: 1, limit: 10 })
Каждый вариант создаёт отдельную сущность в системе отслеживания.
Это позволяет:
Когда запрос перестаёт быть активным и истекает время хранения, RTK Query удаляет его из кэша.
При этом удаляются:
Очистка выполняется автоматически внутри middleware RTK Query и не требует ручного вмешательства.
Отслеживание запросов интегрировано в общий жизненный цикл Redux. Каждый action, связанный с RTK Query, проходит через middleware, где обновляется состояние кэша.
Это обеспечивает:
Каждое изменение подписок фиксируется как событие в store, что делает систему полностью наблюдаемой.
Если компонент, использующий запрос, размонтируется и затем снова монтируется:
Если данные были удалены из-за истечения времени хранения, выполняется новый сетевой запрос.
Отслеживание запросов учитывает специальные параметры управления:
skip отключает создание подпискиpollingInterval поддерживает периодические
обновленияПри skip = true запрос не регистрируется в системе
отслеживания, что полностью исключает его из кэширования и подписок.
Polling, напротив, поддерживает активный статус запроса и увеличивает частоту обновлений без участия пользователя.
RTK Query гарантирует, что все подписчики одного запроса получают одинаковое состояние данных. Обновление кэша автоматически синхронизируется между всеми компонентами.
Это достигается через:
Любое изменение данных мгновенно распространяется на всех подписчиков без дополнительных усилий с их стороны.