Middleware и enhancers

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


Middleware в RTK Query является центральным механизмом, через который проходят все операции, связанные с запросами: отправка, кэширование, инвалидация, повторные запросы, подписки и очистка состояния.

Основной middleware создаётся через createApi и подключается к Redux store автоматически как часть api.middleware.

Базовая интеграция middleware

import { configureStore } from '@reduxjs/toolkit'
import { api } from './api'

export const store = configureStore({
  reducer: {
    [api.reducerPath]: api.reducer,
  },
  middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware().concat(api.middleware),
})

Здесь происходит ключевое расширение store:

  • api.reducer управляет состоянием кэша и запросов
  • api.middleware перехватывает actions, связанные с API

Что делает api.middleware внутри

Middleware RTK Query не просто обрабатывает async действия, а формирует полноценную систему управления запросами.

Основные обязанности middleware:

  • запуск HTTP-запросов через fetchBaseQuery или кастомный baseQuery
  • управление жизненным циклом query/mutation
  • дедупликация одинаковых запросов
  • кэширование результатов
  • автоматическое повторное выполнение при изменении аргументов
  • инвалидация тегов
  • управление подписками на данные
  • отмена запросов при размонтировании компонентов

Поток обработки запроса через middleware

При вызове:

const { data } = useGetUsersQuery()

происходит следующая цепочка:

  1. Хук диспатчит action api/executeQuery/pending

  2. middleware перехватывает action

  3. выполняется baseQuery

  4. результат превращается в:

    • api/executeQuery/fulfilled
    • или api/executeQuery/rejected
  5. reducer обновляет cache state

  6. подписанные компоненты получают обновление


Внутренняя архитектура middleware

RTK Query middleware можно рассматривать как слой оркестрации между Redux и сетевым уровнем.

Компоненты внутри middleware:

  • query lifecycle manager
  • subscription tracker
  • request deduplicator
  • cache lifecycle controller
  • tag invalidation engine

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

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

Если два компонента одновременно вызывают:

useGetUsersQuery()

RTK Query:

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

Это реализовано через внутренний registry активных запросов.


Управление подписками

Каждый useQuery создаёт подписку на cache entry.

Middleware отслеживает:

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

При отсутствии подписчиков возможны действия:

  • удаление cache entry
  • задержанная очистка (cacheTime / keepUnusedDataFor)

Инвалидация тегов через middleware

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

Пример:

getUsers: builder.query({
  query: () => '/users',
  providesTags: ['Users'],
})

updateUser: builder.mutation({
  query: (user) => ({
    url: `/users/${user.id}`,
    method: 'PUT',
    body: user,
  }),
  invalidatesTags: ['Users'],
})

Middleware выполняет:

  1. фиксирует mutation completion
  2. проверяет invalidatesTags
  3. находит связанные queries
  4. запускает refetch

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

baseQuery — это низкоуровневая функция выполнения запроса.

Middleware:

  • вызывает baseQuery
  • оборачивает результат
  • добавляет retry logic (если настроено)
  • контролирует abort signals

AbortController и отмена запросов

RTK Query middleware автоматически использует AbortController.

Сценарий:

  • компонент размонтируется
  • подписка исчезает
  • middleware вызывает abort()
  • сетевой запрос отменяется

Это предотвращает:

  • утечки памяти
  • race conditions
  • обновление state после unmount

Enhancers в RTK Query

Если middleware управляет потоком действий, то enhancers модифицируют сам store.

RTK Query использует store enhancer для:

  • подключения API slice
  • синхронизации reducer + middleware
  • расширения store функциональности

Архитектура enhancers

Enhancer создаётся внутри createApi и автоматически применяется через configureStore.

Он обеспечивает:

  • корректную инициализацию cache reducer
  • доступ middleware к API instance
  • привязку endpoint definitions к store lifecycle

Связь middleware и enhancer

Middleware и enhancer работают как единая система:

  • enhancer создаёт инфраструктуру store
  • middleware управляет runtime поведением

Упрощённая модель:

store enhancer → создаёт API контекст
middleware → управляет запросами в runtime
reducer → хранит cache state

Порядок выполнения middleware в цепочке Redux

RTK Query middleware работает внутри стандартного pipeline Redux middleware.

Порядок:

  1. Redux action dispatch
  2. default middleware (thunk, serializable check)
  3. api.middleware
  4. reducers

Важно, что порядок подключения влияет на поведение кэша и побочных эффектов.


Кастомные middleware вместе с RTK Query

RTK Query не ограничивает использование дополнительных middleware.

Пример:

middleware: (getDefaultMiddleware) =>
  getDefaultMiddleware()
    .concat(loggerMiddleware)
    .concat(api.middleware)

Порядок важен:

  • middleware до api.middleware может модифицировать запросы
  • middleware после может наблюдать результат

Интеграция с Redux DevTools

Middleware обеспечивает корректную трассировку действий:

  • query initiated
  • query fulfilled
  • query rejected
  • mutation initiated

Каждое событие проходит через middleware pipeline, что позволяет DevTools отображать полную цепочку запроса.


Retry и middleware

RTK Query поддерживает retry через расширения baseQuery.

Middleware управляет:

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

При этом retry логика остаётся изолированной от компонентов.


Оптимизация через middleware

Middleware выполняет ряд оптимизаций:

  • batching одинаковых запросов
  • предотвращение лишних refetch
  • управление stale-time логикой
  • сокращение сетевых вызовов при повторной подписке

Внутренний event loop RTK Query

Можно представить middleware как цикл обработки событий:

action → middleware → baseQuery → response → middleware → reducer → state update → re-render

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


Особенности работы с SSR и middleware

В server-side rendering сценариях middleware:

  • выполняет запросы синхронно через store dispatch
  • позволяет prefetch данных до рендера
  • сериализует cache state для передачи на клиент

Hydration и middleware

При гидрации состояния:

  • enhancer восстанавливает API slice state
  • middleware продолжает обработку новых запросов
  • старый cache может быть переиспользован

Итоговая модель поведения

RTK Query middleware и enhancers формируют слой, который превращает Redux из системы управления состоянием в полноценный data-fetching engine.

Ключевые принципы:

  • все запросы проходят через middleware pipeline
  • enhancer создаёт инфраструктуру API slice
  • cache управляется централизованно
  • подписки и инвалидации автоматизированы
  • сетевой слой полностью абстрагирован