TanStack Query: Майстерність Керування Станом Сервера

Синхронізація Даних: Життєвий Цикл Запиту

Одна з найскладніших речей для розуміння в TanStack Query — це те, як і коли він вирішує оновити дані. "Чому воно знову робить запит?", "Чому дані зникли?" — типові питання.

Синхронізація Даних: Життєвий Цикл Запиту

Одна з найскладніших речей для розуміння в TanStack Query — це те, як і коли він вирішує оновити дані. "Чому воно знову робить запит?", "Чому дані зникли?" — типові питання.

У цій главі ми розберемо state machine (машину станів), яка живе всередині кожного запиту.

Стани Запиту

Кожен запит у будь-який момент часу перебуває в одному з цих станів:

Loading diagram...
graph TD
    A[Fetching] -->|Success| B[Fresh]
    B -->|staleTime elapsed| C[Stale]
    C -->|Window Focus / Mount| A
    C -->|Component Unmount| D[Inactive]
    D -->|gcTime elapsed| E[Deleted (GC)]
    D -->|Component Mount| C

    style B fill:#10b981,stroke:#059669,color:#fff
    style C fill:#f59e0b,stroke:#d97706,color:#fff
    style A fill:#3b82f6,stroke:#2563eb,color:#fff
    style D fill:#6b7280,stroke:#4b5563,color:#fff
```mermaid
  1. Fetching: Дані завантажуються (в польоті).
  2. Fresh (Свіжі): Дані актуальні. Query не буде намагатися їх оновити, навіть якщо ви попросите.
  3. Stale (Застарілі): Дані є, але вони "протухли". Query поверне їх вам, але у фоні спробує оновити.
  4. Inactive: Цей запит зараз не використовується жодним компонентом.
  5. Deleted: Видалено з пам'яті збирачем сміття (Garbage Collector).

staleTime vs gcTime

Це два найважливіші налаштування, які ви повинні розрізняти.

staleTime (Час Свіжості)

Питання: "Скільки часу дані вважаються ідеальними?"

  • Default: 0 (нуль).
  • Сенс: За замовчуванням дані стають застарілими миттєво після отримання.
  • Поведінка:
    • Якщо staleTime: 0: При кожному вході на сторінку або фокусі вікна буде background refetch.
    • Якщо staleTime: 5000 (5 сек): Протягом 5 секунд після запиту дані вважаються свіжими. Жодних запитів не буде, навіть якщо ви перемонтуєте компонент 100 разів.
Для даних, які рідко змінюються (наприклад, список категорій або налаштування користувача), сміливо ставте staleTime: Infinity або велике значення (наприклад, 10 хвилин).
useQuery({
  queryKey: ['settings'],
  queryFn: fetchSettings,
  staleTime: 1000 * 60 * 10, // 10 хвилин
});

gcTime (Garbage Collection Time)

Раніше відомий як cacheTime. Питання: "Скільки часу тримати дані в пам'яті, якщо їх ніхто не бачить?"

  • Default: 5 хвилин.
  • Сенс: Коли останній компонент, що використовував ці дані, демонтується (unmount), запит переходить у стан Inactive. Таймер запускається.
  • Поведінка:
    • Якщо користувач повернеться на сторінку через 2 хвилини: Дані миттєво з'являться з кешу. Таймер скинеться.
    • Якщо користувач повернеться через 6 хвилин: Даних немає. Буде "hard loading" (скелетон).
gcTime не має нічого спільного з тим, коли робити запит. Воно лише про звільнення пам'яті.

Тригери Оновлення (Refetch Triggers)

Коли дані знаходяться у стані Stale, TanStack Query чекає на "подію", щоб їх оновити.

  1. refetchOnWindowFocus (Default: true)
    • Коли користувач перемикає вкладку браузера і повертається.
    • Це гарантує, що користувач завжди бачить актуальні дані після повернення до роботи.
  2. refetchOnMount (Default: true)
    • Коли компонент монтується. Якщо дані Stale — оновити.
  3. refetchOnReconnect (Default: true)
    • Коли зник і знову з'явився інтернет.

Як вимкнути "зайві" запити?

Якщо вас дратує, що запити літають постійно (наприклад, під час розробки), ви можете налаштувати це глобально або локально.

// Локально для одного запиту
useQuery({
    queryKey: ['todos'],
    queryFn: fetchTodos,
    refetchOnWindowFocus: false, // Не оновлювати при фокусі
    staleTime: 1000 * 60, // Не оновлювати частіше ніж раз на хвилину
})

Polling (Інтервальне Оновлення)

Іноді вам потрібно оновлювати дані кожні N секунд (наприклад, ціни на біржі або статус чату).

useQuery({
    queryKey: ['stock-price'],
    queryFn: fetchPrice,
    // Оновлювати кожні 2 секунди
    refetchInterval: 2000,
    // Навіть якщо вкладка браузера не активна (background)
    refetchIntervalInBackground: true,
})

Статус fetchStatus

У v4/v5 з'явився новий проперті fetchStatus, який працює в парі з status.

status: pending | error | success (Про дані) fetchStatus: fetching | paused | idle (Про мережу)

Сценарій: Ви зробили запит, але інтернет зник.

  • status: pending (даних ще немає).
  • fetchStatus: paused (запит на паузі, чекає мережі).

Це дозволяє показувати UI типу "Waiting for connection...", замість простого спіннера, який крутиться вічно.

const { status, fetchStatus } = useQuery(...);

if (status === 'pending' && fetchStatus === 'paused') {
  return <div>No Internet connection...</div>;
}

Далі: Мутації та Зміна Даних

Copyright © 2026