TanStack Vue Query: запросы, кэш, инвалидация

↑ 5.2 Состояние: Pinia, SSOT, Vue Query · ← Предыдущая · → Следующая

Обязательно~3 мин чтенияУровень: middle

Зачем это на собесе

Стандарт работы с серверным состоянием; спрашивают ключи, staleTime, инвалидацию.

Объяснение

// main.ts
app.use(VueQueryPlugin, { queryClientConfig: { defaultOptions: { queries: { staleTime: 30_000, retry: 2, refetchOnWindowFocus: false } } } });
 
// Запрос
const filters = ref({ status: "paid", page: 1 });
const { data, isPending, isFetching, isError, error, refetch } = useQuery({
  queryKey: ["orders", filters],                        // ключ включает реактивные параметры — смена → новый запрос
  queryFn: ({ signal }) => api.getOrders(filters.value, { signal }),   // signal для отмены
  staleTime: 60_000,
  placeholderData: keepPreviousData,                    // без «мигания» при смене страницы
  enabled: computed(() => !!userId.value),              // зависимые запросы
  select: (d) => d.items,                               // преобразование
});

Ключевые понятия:

ПонятиеСмысл
queryKeyидентификатор кэша; массив, включает все параметры
staleTimeсколько данные считаются свежими (без фонового обновления)
gcTime (cacheTime)сколько неиспользуемые данные хранятся в кэше
isPending / isFetchingнет данных вообще / идёт любой запрос (включая фоновый)
status: pending/error/successсостояние данных
Refetchпри монтировании, фокусе окна, восстановлении сети, интервал
Дедупликацияодинаковые запросы объединяются
Retryповторы с экспоненциальной паузой
queryClientдоступ к кэшу: getQueryData, setQueryData, invalidateQueries, prefetchQuery

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

const qc = useQueryClient();
qc.invalidateQueries({ queryKey: ["orders"] });                 // все запросы, ключ которых начинается с "orders"
qc.setQueryData(["order", id], updated);                        // точечное обновление кэша
await qc.prefetchQuery({ queryKey: ["order", id], queryFn: () => api.getOrder(id) });   // предзагрузка на hover

Бесконечные списки — useInfiniteQuery (getNextPageParam), пагинация — placeholderData, SSR — dehydrate/hydrate, DevTools — @tanstack/vue-query-devtools.

Организация: фабрики ключей и хуки на сущность (useOrders, useOrder), общий слой API, обработка ошибок через QueryCache.onError.

Нюансы и подводные камни

  • Реактивные параметры нужно передавать как ref/computed в queryKey, иначе запрос не перезапустится.
  • staleTime: 0 (по умолчанию) вызывает частые перезапросы — настройте под данные.
  • Деструктурированные значения — refs, в шаблоне разворачиваются, в скрипте — .value.
  • Не храните копию data в локальном ref без нужды.
  • Отменяйте запросы через signal.

Практика

  1. Замените ручную загрузку списка на useQuery с фильтрами в ключе.
  2. Настройте staleTime, placeholderData: keepPreviousData для пагинации.
  3. Предзагрузите карточку при наведении на строку таблицы.

Вопросы с ответами

Связанные темы