Принудительная очистка кэша

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

Принудительная очистка кэша становится необходимой в ситуациях, когда стандартные механизмы инвалидации (tags, refetch, refetchOnMount) не покрывают жизненный цикл данных. Типичные случаи включают:

  • полный выход пользователя из системы с очисткой чувствительных данных
  • переключение между радикально разными контекстами данных (multi-tenant приложения)
  • необходимость сброса состояния API после критической ошибки
  • тестовые сценарии и hot-reload в разработке
  • ручное управление памятью при долгоживущих SPA без перезагрузки

Внутренняя структура кэша и влияние очистки

RTK Query хранит данные в нескольких слоях:

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

Принудительное вмешательство может затронуть как отдельные записи, так и весь API-слайс целиком. Это важно, потому что частичная очистка не всегда приводит к повторному запросу данных — поведение зависит от наличия подписчиков.


Полная очистка через resetApiState

Основной механизм полного сброса состояния — resetApiState. Он возвращает API slice к начальному состоянию, как будто запросов никогда не выполнялось.

import { api } from './apiSlice';
import { store } from './store';

store.dispatch(api.util.resetApiState());

После выполнения:

  • удаляются все queries
  • сбрасываются mutations
  • очищаются providedTags
  • уничтожаются активные подписки
  • кэш перестаёт содержать какие-либо данные

Ключевая особенность — это именно «жёсткий» сброс. Даже активные компоненты теряют данные и инициируют повторные запросы при следующем рендере.


Очистка конкретного запроса через removeQueryResult

Более точечный механизм — удаление одного кэширующего ключа:

store.dispatch(
  api.util.removeQueryResult('getUser', { id: 5 })
);

Это действие:

  • удаляет только конкретный entry из queries
  • не трогает остальные запросы
  • не инвалидирует теги автоматически
  • не влияет на другие подписки

Если в момент удаления существует активная подписка, RTK Query может немедленно выполнить повторный запрос, так как данные считаются отсутствующими.


Инвалидация через tags как промежуточный механизм

Хотя tag-based система не является прямой очисткой, она часто используется как мягкая форма принудительного обновления.

getUser: builder.query({
  query: (id) => `user/${id}`,
  providesTags: (result, error, id) => [{ type: 'User', id }]
})

И последующая инвалидация:

store.dispatch(
  api.util.invalidateTags([{ type: 'User', id: 5 }])
);

Поведение:

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

Это важное отличие от removeQueryResult, где данные исчезают немедленно.


Очистка через unsubscribe и жизненный цикл подписок

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

createApi({
  reducerPath: 'api',
  keepUnusedDataFor: 60
})

Принудительная очистка часто комбинируется с управлением подписками:

  • размонтирование компонентов
  • удаление query через removeQueryResult
  • сброс всего API через resetApiState

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


Сброс через refetch и forced refetch поведение

RTK Query не предоставляет отдельного метода «force clear and refetch», но аналогичный эффект достигается комбинацией:

dispatch(api.util.invalidateTags(['User']));

или через изменение аргументов запроса:

useGetUserQuery({ id: userId }, { refetchOnMountOrArgChange: true });

Изменение аргумента приводит к:

  • созданию нового cache key
  • игнорированию старого результата
  • загрузке новых данных

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

В SPA с авторизацией часто возникает необходимость полного сброса API состояния при logout:

const logout = () => {
  dispatch(authSlice.actions.logout());
  dispatch(api.util.resetApiState());
};

Такой подход предотвращает:

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

Иногда дополнительно очищаются persisted store (если используется redux-persist), иначе кэш может восстановиться после reload.


Частичная очистка через middleware и ручные экшены

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

const apiCleanupMiddleware = (store) => (next) => (action) => {
  if (action.type === 'auth/logout') {
    store.dispatch(api.util.resetApiState());
  }
  return next(action);
};

Также возможна интеграция с бизнес-логикой:

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

Влияние принудительной очистки на активные запросы

При очистке кэша важно учитывать состояние активных запросов:

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

Это создаёт эффект «гонки состояния», особенно при массовом resetApiState.


Оптимизация сценариев очистки

Чрезмерное использование полной очистки приводит к:

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

Поэтому часто применяется комбинированная стратегия:

  • invalidateTags для обновления данных
  • removeQueryResult для точечных случаев
  • resetApiState только для глобальных событий
  • keepUnusedDataFor для контроля времени жизни кэша

Состояние кэша после очистки и повторное построение данных

После принудительной очистки RTK Query восстанавливает кэш постепенно:

  • первый вызов useQuery создаёт новый entry
  • подписка инициирует сетевой запрос
  • результаты снова нормализуются в queries
  • теги пересобираются заново

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