Параметры и опции хука

Хук useQuery в Redux Toolkit RTK Query представляет собой основной инструмент для декларативного выполнения запросов к серверу и получения состояния этих запросов в компоненте. Его поведение полностью управляется входными параметрами и набором опций, которые определяют жизненный цикл запроса, кэширование, повторные запросы, выборку данных и стратегию обновления.


Базовая сигнатура useQuery

Типичная форма использования:

const { data, error, isLoading, isFetching } = useGetUsersQuery(arg, options)

Где:

  • arg — аргумент запроса (параметры запроса)
  • options — объект конфигурации поведения запроса

Аргумент запроса (query argument)

Первый параметр хука — это входные данные для endpoint’а.

Примитивные значения

useGetUserQuery(1)
useGetPostsQuery('latest')

Используется, когда endpoint ожидает один параметр.

Объекты как аргументы

useGetPostsQuery({
  page: 1,
  limit: 20,
  sort: 'desc'
})

Объектный аргумент позволяет:

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

Отсутствие аргумента

Некоторые endpoint’ы не требуют параметров:

useGetSettingsQuery()

Опция skip

Одна из ключевых опций управления выполнением запроса.

Назначение

Полностью отключает выполнение запроса.

const { data } = useGetUserQuery(id, {
  skip: !id
})

Поведение

  • true — запрос не выполняется
  • false — запрос выполняется как обычно

Типичные сценарии

  • ожидание загрузки параметров
  • условные запросы
  • защита от undefined значений

skipToken как альтернативный способ пропуска

Вместо skip можно использовать специальный токен:

import { skipToken } from '@reduxjs/toolkit/query'

const { data } = useGetUserQuery(id ?? skipToken)

Особенности:

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

pollingInterval

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

useGetNotificationsQuery(null, {
  pollingInterval: 5000
})

Поведение

  • значение указывается в миллисекундах
  • запрос выполняется циклически
  • прекращается при размонтировании компонента

Использование

  • чаты
  • уведомления
  • live-дашборды
  • мониторинг состояния системы

refetchOnMountOrArgChange

Контролирует повторный запрос при монтировании компонента.

Варианты

useGetUserQuery(id, {
  refetchOnMountOrArgChange: true
})

Логика работы

  • false — используется кэш без повторного запроса
  • true — всегда выполняется новый запрос
  • число (секунды) — повторный запрос при устаревании данных

refetchOnFocus

Автоматический повтор запроса при возврате фокуса на вкладку браузера.

useGetUserQuery(id, {
  refetchOnFocus: true
})

Механизм

RTK Query отслеживает событие visibilitychange и при возвращении фокуса:

  • проверяет актуальность данных
  • инициирует refetch при необходимости

Применение

  • финансовые данные
  • динамические списки
  • админ-панели

refetchOnReconnect

Запуск повторного запроса при восстановлении интернет-соединения.

useGetUserQuery(id, {
  refetchOnReconnect: true
})

Поведение

  • отслеживает online событие браузера
  • выполняет запрос после восстановления сети
  • полезно при нестабильном соединении

selectFromResult

Одна из наиболее мощных и недооценённых опций.

Назначение

Позволяет выбирать и преобразовывать часть результата запроса.

const { userName } = useGetUserQuery(id, {
  selectFromResult: ({ data }) => ({
    userName: data?.name
  })
})

Преимущества

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

Пример фильтрации

useGetPostsQuery(undefined, {
  selectFromResult: ({ data }) => ({
    posts: data?.filter(post => post.published)
  })
})

Влияние на производительность

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


transformResponse (на уровне endpoint, но влияет на хук)

Хотя не является параметром хука, часто используется совместно.

getUser: builder.query({
  query: (id) => `user/${id}`,
  transformResponse: (response) => response.data
})

Роль

  • нормализация ответа API
  • упрощение структуры данных
  • подготовка данных для UI

keepUnusedDataFor

Контролирует время хранения данных в кэше после отписки.

useGetUserQuery(id, {
  keepUnusedDataFor: 60
})

Поведение

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

subscribe и модель подписок

Каждый вызов useQuery создаёт подписку на данные в store.

Логика:

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

refetch как метод управления

Хук возвращает функцию refetch:

const { refetch } = useGetUserQuery(id)

refetch()

Использование

  • ручное обновление данных
  • кнопка “обновить”
  • реакция на внешние события

isFetching vs isLoading

Параметры состояния запроса имеют различную семантику.

isLoading

  • первый запрос
  • отсутствие кэша

isFetching

  • любой активный запрос
  • включая фоновые обновления
const { isLoading, isFetching } = useGetUserQuery(id)

error и обработка ошибок

const { error } = useGetUserQuery(id)

Особенности

  • может содержать HTTP ошибки
  • может быть сериализованным объектом
  • зависит от baseQuery

Комбинирование опций

Реальные сценарии часто используют несколько параметров одновременно.

useGetUserQuery(id, {
  skip: !id,
  pollingInterval: 10000,
  refetchOnFocus: true,
  refetchOnReconnect: true,
  selectFromResult: ({ data, isFetching }) => ({
    user: data,
    loading: isFetching
  })
})

Поведение кэширования в связке с параметрами

Каждый параметр влияет на кэш-ключ:

  • arg формирует уникальный cache key
  • одинаковые аргументы используют общий кэш
  • skip исключает участие в кэшировании
  • refetch обновляет существующий entry

Управление жизненным циклом через опции

RTK Query строит жизненный цикл запроса на основе конфигурации:

  • инициализация через arg
  • подписка через хук
  • обновление через polling или refetch
  • деактивация через unmount
  • очистка через keepUnusedDataFor

Влияние опций на ререндеринг

Опции напрямую влияют на количество обновлений компонента:

  • selectFromResult минимизирует ререндеры
  • pollingInterval увеличивает частоту обновлений
  • isFetching вызывает дополнительные обновления UI
  • skip полностью исключает рендер запросной логики

Особенности стабильности аргументов

Аргумент запроса сравнивается по строгому равенству:

  • примитивы сравниваются напрямую
  • объекты сравниваются по ссылке
useGetPostsQuery({ page: 1 }) // каждый рендер = новый запрос

Решение — мемоизация:

const params = useMemo(() => ({ page: 1 }), [])

useGetPostsQuery(params)

Взаимодействие с middleware

Опции хука работают совместно с middleware слоя RTK:

  • кэширование
  • дедупликация запросов
  • повторные попытки (retry)
  • синхронизация состояния

Дедупликация запросов

RTK Query автоматически предотвращает дублирование:

  • одинаковый arg
  • одинаковый endpoint
  • активная подписка

Повторный вызов хука не создаёт новый HTTP-запрос, если данные уже загружаются или закэшированы.


Управление поведением через конфигурацию store

Некоторые опции глобально настраиваются:

createApi({
  keepUnusedDataFor: 30,
  refetchOnFocus: true,
  refetchOnReconnect: true
})

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


Поведение при смене аргумента

Изменение arg запускает полный цикл:

  • отписка от старого запроса
  • проверка кэша
  • новый запрос при необходимости
  • обновление подписок UI
useGetUserQuery(userId)

Смена userId приводит к новому cache key.