Удаление данных из кеша

Кеш в TanStack Query хранит результаты запросов, состояние загрузки, ошибки и метаданные. Со временем часть данных становится ненужной:

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

Для подобных сценариев TanStack Query предоставляет механизмы удаления данных из кеша.

Удаление данных отличается от инвалидирования. Инвалидация помечает данные устаревшими и может инициировать повторную загрузку, тогда как удаление полностью уничтожает запись из кеша.


Разница между invalidateQueries и removeQueries

Очень важно понимать различие между двумя подходами.

invalidateQueries

queryClient.invalidateQueries({
    queryKey: ['posts']
});

Поведение:

  • запрос помечается устаревшим;
  • данные остаются в кеше;
  • возможен автоматический refetch;
  • компоненты продолжают получать старые данные до обновления.

removeQueries

queryClient.removeQueries({
    queryKey: ['posts']
});

Поведение:

  • запрос полностью удаляется из Query Cache;
  • данные исчезают из памяти;
  • состояние запроса уничтожается;
  • при повторном использовании потребуется новая загрузка.

Полное удаление запросов

removeQueries

Основной метод удаления кеша:

queryClient.removeQueries();

Такой вызов удаляет все запросы из кеша.

На практике обычно используются фильтры.


Удаление по queryKey

Удаление конкретного запроса

queryClient.removeQueries({
    queryKey: ['user']
});

Удаляется только запрос:

['user']

Удаление группы запросов

queryClient.removeQueries({
    queryKey: ['posts']
});

Будут удалены:

['posts']
['posts', 1]
['posts', 2]
['posts', 'popular']

Поскольку TanStack Query использует частичное совпадение ключей.


Точное совпадение ключей

exact: true

queryClient.removeQueries({
    queryKey: ['posts'],
    exact: true
});

Теперь удаляется только:

['posts']

Но не:

['posts', 1]
['posts', 'popular']

Удаление через predicate

Для сложной логики применяется predicate.

Пример

queryClient.removeQueries({
    predicate: (query) => {
        return query.queryKey[0] === 'posts';
    }
});

Удаление по параметрам

queryClient.removeQueries({
    predicate: (query) => {
        return query.queryKey[0] === 'posts'
            && query.queryKey[1]?.archived === true;
    }
});

Удаление inactive-запросов

В кеше могут храниться запросы, которые больше не используются компонентами.

inactive

queryClient.removeQueries({
    queryKey: ['posts'],
    type: 'inactive'
});

Удаляются только неактивные запросы.

Активные запросы продолжают существовать.


Удаление active-запросов

queryClient.removeQueries({
    queryKey: ['posts'],
    type: 'active'
});

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


Удаление всех запросов после logout

Один из самых распространённых сценариев.

Полный сброс кеша

const logout = async () => {
    await api.logout();

    queryClient.removeQueries();
};

После выхода пользователя:

  • удаляются персональные данные;
  • очищаются списки;
  • уничтожаются приватные запросы.

clear и removeQueries

TanStack Query предоставляет ещё один метод.

clear

queryClient.clear();

Разница:

Метод Поведение
removeQueries удаляет только запросы
clear очищает QueryCache и MutationCache

Что удаляет clear

queryClient.clear();

Удаляются:

  • все queries;
  • все mutations;
  • подписчики;
  • состояния загрузки;
  • ошибки.

Это полный сброс клиента.


removeQueries и gcTime

По умолчанию TanStack Query автоматически очищает неиспользуемые запросы через gcTime.

Например:

const queryClient = new QueryClient({
    defaultOptions: {
        queries: {
            gcTime: 1000 * 60 * 5
        }
    }
});

Через 5 минут неактивный запрос удалится автоматически.

Но removeQueries позволяет удалить данные немедленно.


Удаление infinite queries

Infinite Query хранится как обычный query.

Пример удаления

queryClient.removeQueries({
    queryKey: ['feed']
});

Удаляются:

  • страницы;
  • pageParams;
  • состояние пагинации;
  • информация о загрузке.

Удаление кеша после смены пользователя

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

Пример

const switchAccount = async (userId) => {
    await auth.loginAs(userId);

    queryClient.clear();
};

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


Удаление чувствительных данных

Некоторые данные нельзя долго хранить в памяти:

  • банковская информация;
  • токены;
  • медицинские данные;
  • приватные документы.

Пример

queryClient.removeQueries({
    queryKey: ['bank-account']
});

Удаление после завершения процесса

Иногда данные нужны только временно.

Пример мастера регистрации

const finishRegistration = async () => {
    await completeRegistration();

    queryClient.removeQueries({
        queryKey: ['registration-draft']
    });
};

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

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

Пример

const switchWorkspace = async (workspaceId) => {
    setWorkspace(workspaceId);

    queryClient.removeQueries({
        queryKey: ['workspace-data']
    });
};

removeQueries не вызывает refetch

Ключевая особенность метода.

queryClient.removeQueries({
    queryKey: ['posts']
});

Запрос не перезагружается автоматически.

Данные просто исчезают.

Новая загрузка произойдёт только если:

  • компонент снова запросит данные;
  • будет вызван refetch;
  • выполнится prefetch;
  • сработает invalidateQueries.

Что происходит с useQuery после удаления

Предположим:

useQuery({
    queryKey: ['posts'],
    queryFn: fetchPosts
});

Если выполнить:

queryClient.removeQueries({
    queryKey: ['posts']
});

то:

  • кеш удаляется;
  • query создаётся заново;
  • useQuery начинает новую загрузку;
  • isLoading становится true.

removeQueries и активные компоненты

Если запрос активен:

queryClient.removeQueries({
    queryKey: ['posts']
});

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

Поэтому удаление активных запросов требует осторожности.


Безопасное удаление inactive-запросов

Наиболее распространённый вариант:

queryClient.removeQueries({
    type: 'inactive'
});

Такой подход:

  • не ломает активный UI;
  • освобождает память;
  • очищает старые данные.

Комбинирование invalidate и remove

Иногда применяется комбинация.

Пример

queryClient.invalidateQueries({
    queryKey: ['posts']
});

queryClient.removeQueries({
    queryKey: ['draft-posts']
});

Где:

  • публичные данные обновляются;
  • временные данные полностью удаляются.

removeQueries внутри mutation

Пример

const deleteAccountMutation = useMutation({
    mutationFn: deleteAccount,
    onSuccess: () => {
        queryClient.clear();
    }
});

После удаления аккаунта весь кеш очищается.


Удаление через Query Filters

removeQueries использует систему Query Filters.

Основные фильтры

queryClient.removeQueries({
    queryKey: ['posts'],
    exact: true,
    type: 'inactive',
    stale: true,
    predicate: (query) => true
});

stale-фильтр

Можно удалять только устаревшие запросы.

Пример

queryClient.removeQueries({
    stale: true
});

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


Массовая очистка кеша

Очистка определённого модуля

queryClient.removeQueries({
    predicate: (query) => {
        return query.queryKey[0] === 'admin';
    }
});

Очистка API-версии

queryClient.removeQueries({
    predicate: (query) => {
        return query.queryKey.includes('v1');
    }
});

removeQueries и persistQueryClient

При использовании persister необходимо учитывать:

  • removeQueries удаляет данные из памяти;
  • persister синхронизирует изменения в storage;
  • удалённые запросы исчезают и из localStorage/sessionStorage.

Удаление кеша при истечении сессии

Пример

window.addEventListener('session-expired', () => {
    queryClient.clear();
});

Очистка при ошибках авторизации

Пример

const handleUnauthorized = () => {
    queryClient.clear();
};

Обычно используется после HTTP 401.


Частичная очистка кеша

В больших приложениях кеш делится по доменам:

['auth']
['posts']
['comments']
['profile']
['notifications']

Это позволяет удалять только нужную область данных.

Пример

queryClient.removeQueries({
    queryKey: ['notifications']
});

Стратегии очистки кеша

Агрессивная очистка

Подходит для:

  • административных панелей;
  • систем с конфиденциальными данными;
  • low-memory устройств.
queryClient.clear();

Мягкая очистка

Подходит для большинства приложений.

queryClient.removeQueries({
    type: 'inactive'
});

Точечная очистка

Используется для конкретных сущностей.

queryClient.removeQueries({
    queryKey: ['draft']
});

Когда удаление лучше инвалидирования

Удаление предпочтительнее если:

  • данные больше не нужны;
  • требуется освободить память;
  • информация конфиденциальна;
  • пользователь вышел из системы;
  • данные не должны отображаться даже временно.

Когда лучше использовать invalidateQueries

Инвалидация предпочтительнее если:

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

Типичные ошибки

Удаление активных запросов без необходимости

queryClient.removeQueries({
    queryKey: ['posts']
});

Может вызывать лишние refetch.


Использование clear вместо removeQueries

queryClient.clear();

Полностью уничтожает состояние клиента и mutations.

Для локальной очистки это слишком агрессивный подход.


Отсутствие сегментации queryKey

Плохой вариант:

['data']

Хороший вариант:

['posts']
['posts', id]
['posts', 'drafts']

Структурированные ключи позволяют безопасно очищать кеш.


Практический пример архитектуры

Ключи запросов

['auth']
['profile']
['posts']
['posts', postId]
['notifications']
['drafts']

Logout

const logout = async () => {
    await api.logout();

    queryClient.clear();
};

Очистка черновиков

queryClient.removeQueries({
    queryKey: ['drafts']
});

Очистка старых уведомлений

queryClient.removeQueries({
    queryKey: ['notifications'],
    type: 'inactive'
});

Внутреннее устройство удаления

При removeQueries:

  1. QueryClient находит подходящие queries.
  2. QueryCache удаляет их.
  3. Удаляются observers.
  4. Освобождаются ссылки на данные.
  5. Компоненты получают уведомления об изменениях.

После этого query перестаёт существовать внутри кеша TanStack Query.