Профилирование и отладка

RTK Query тесно интегрирован с экосистемой Redux Toolkit и наследует её модель потоков данных: единый store, предсказуемые обновления, иммутабельные изменения и подписочная модель через React-обвязку. Это делает поведение данных формально детерминированным, но при неправильной настройке приводит к избыточным перезапросам, лишним ререндерам и разрастанию кэша.

Профилирование в RTK Query сводится к трём уровням: сетевые запросы, состояние кэша и рендеринг компонентов.


Архитектурные точки наблюдения

RTK Query строит работу вокруг нескольких ключевых слоёв:

  • API slice (createApi)
  • Base query
  • Query cache (Redux state)
  • Subscriptions (React hooks)
  • Tags invalidation mechanism

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


Инструменты наблюдения состояния

Redux DevTools как первичный источник истины

RTK Query полностью отражает своё состояние в Redux store под ключом:

state.api

Внутри него находятся:

  • queries — активные запросы и их результаты
  • mutations — состояние мутаций
  • provided — теги для инвалидации
  • subscriptions — активные подписки компонентов
  • config — настройки API слоя

Типичная проблема — разрастание queries из-за параметров, которые меняются по ссылке (object identity), например:

useGetUsersQuery({ page: 1, filter: { role: 'admin' } })

Каждый новый объект создаёт новый cache key, даже если данные эквивалентны.


Профилирование сетевых запросов

Контроль дублирующих запросов

RTK Query по умолчанию дедуплицирует запросы, но только при совпадении:

  • endpoint name
  • serialized query arguments
  • baseQuery configuration

Ошибки часто возникают при:

  • нестабильных объектах аргументов
  • кастомных serializeQueryArgs
  • динамических headers

Анализ через Network tab

В браузере важно отслеживать:

  • повторяющиеся запросы с одинаковыми параметрами
  • запросы при каждом фокусе окна
  • запросы при монтировании/размонтаже компонентов
  • refetchOnMountOrArgChange

Особое внимание:

  • refetchOnFocus
  • refetchOnReconnect
  • pollingInterval

Эти механизмы часто создают “невидимую нагрузку”.


Подписки и утечки рендеринга

RTK Query использует модель подписок: каждый useQuery создаёт subscription в store.

Основные проблемы:

1. Лишние подписки

Компоненты, которые часто перемонтируются, создают лишнюю нагрузку:

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

2. Дрожание подписок (subscription thrashing)

Возникает при:

  • изменении аргументов на каждый рендер
  • создании inline объектов
  • несогласованной нормализации данных

Проверка через state.api.subscriptions

В Redux DevTools можно наблюдать:

subscriptions: {
  "getUsers({page:1})": {
    "a1b2c3": 1
  }
}

Если количество подписок растёт без причины — проблема в жизненном цикле компонентов.


selectFromResult как инструмент оптимизации

Одним из ключевых механизмов контроля рендеров является selectFromResult.

Он позволяет ограничить данные, которые триггерят ререндер:

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

Профилировочная ценность:

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

Ошибка: возвращение нового объекта без мемоизации приводит к обратному эффекту.


Анализ кэша и нормализация данных

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

1. Разрастание кэша

Причины:

  • параметры запроса не стабилизированы
  • динамические фильтры создают новые ключи
  • отсутствие reuse аргументов

2. Устаревшие записи

При неправильной работе тегов:

providesTags: ['Users']
invalidatesTags: ['Users']

Проблема возникает, если:

  • теги слишком общие
  • отсутствует granular invalidation

Инвалидация и скрытая нагрузка

Механизм providesTags / invalidatesTags может быть источником каскадных обновлений.

Типичные паттерны деградации:

  • один mutation инвалидирует слишком много queries
  • цепочка refetch-запросов после одного изменения
  • циклические обновления через optimistic updates

Отладка baseQuery

baseQuery — место, где часто скрываются ошибки:

1. Логирование запросов

Оборачивание baseQuery:

const baseQueryWithLogger = async (args, api, extraOptions) => {
  console.time('request')
  const result = await fetchBaseQuery({ baseUrl })(args, api, extraOptions)
  console.timeEnd('request')
  return result
}

2. Ошибки сериализации

  • некорректные headers
  • non-serializable params
  • Date/Map/Set в аргументах

Использование Redux DevTools для анализа производительности

Ключевые сигналы:

  • частые api/executeQuery/pending
  • повторяющиеся fulfilled с одинаковыми аргументами
  • чередование unsubscribesubscribe

Профилирование рендеров React

RTK Query тесно связан с React render lifecycle.

Инструменты:

  • React DevTools Profiler
  • Highlight updates
  • Flamegraph анализа

Типичная проблема:

  • компонент подписан на весь query result вместо частичного селектора

refetch поведение и скрытые триггеры

RTK Query может выполнять refetch без явного вызова:

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

Особенно важно:

refetchOnMountOrArgChange: true
refetchOnFocus: true
refetchOnReconnect: true

Эти параметры часто создают “фантомную активность”.


Профилирование polling

Polling — один из наиболее дорогих механизмов.

Проблемы:

  • несколько компонентов с одинаковым pollingInterval
  • отсутствие очистки при unmount
  • конкурирующие polling-циклы

Симптом:

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

Изоляция проблем через отключение механизмов

Для диагностики последовательно отключаются:

  • polling
  • refetchOnFocus
  • refetchOnMountOrArgChange
  • tags invalidation

Это позволяет определить источник нестабильного поведения.


Анализ стабильности аргументов запросов

Ключевой фактор производительности — стабильность аргументов.

Проблемные конструкции:

useGetPostsQuery({
  filters: {
    search: term
  }
})

Даже если term не меняется, объект пересоздаётся.

Решение на уровне архитектуры:

  • мемоизация аргументов
  • нормализация фильтров
  • использование примитивов вместо объектов

Слежение за жизненным циклом query

RTK Query проходит стадии:

  • pending
  • fulfilled
  • rejected
  • removed

Отслеживание этих переходов в Redux DevTools позволяет выявить:

  • неожиданные повторные запросы
  • сброс кэша
  • утечки подписок

Диагностика через временные метрики

Основные метрики:

  • время до первого ответа (TTFB)
  • время кэш-хита vs network fetch
  • время жизни cache entry
  • частота refetch за единицу времени

Эти метрики часто показывают архитектурные проблемы раньше, чем UI симптомы.


Типовые источники деградации

  • нестабильные query arguments
  • чрезмерная инвалидация тегов
  • дублирующие подписки компонентов
  • отсутствие memoization в селекторах
  • активные polling-циклы
  • refetchOnFocus без необходимости
  • рост числа уникальных cache keys

Структурный подход к отладке

Отладка RTK Query сводится к последовательному разложению поведения:

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

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