Периодическое обновление

Периодическое обновление данных в TanStack Query реализуется через механизм автоматического повторного запроса (refetching), который позволяет поддерживать кэш в актуальном состоянии без ручного вмешательства. Это особенно важно для приложений с динамическими данными: дашборды, чаты, торговые панели, системы мониторинга, административные интерфейсы.

TanStack Query управляет серверным состоянием через кэш, привязанный к ключам запросов (queryKey). По умолчанию данные остаются в кэше до тех пор, пока не произойдёт одно из событий: инвалидизация, повторный запрос при фокусе окна или ручной вызов refetch.

Периодическое обновление добавляет третий автоматический источник актуализации данных — таймер, запускающий refetch через заданный интервал.

Основной параметр, отвечающий за это поведение:

useQuery({
  queryKey: ['users'],
  queryFn: fetchUsers,
  refetchInterval: 5000
})

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

Постоянное и условное обновление

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

Постоянный интервал

useQuery({
  queryKey: ['orders'],
  queryFn: fetchOrders,
  refetchInterval: 10000
})

Запрос выполняется каждые 10 секунд независимо от состояния приложения.

Условный интервал

Функция вместо числа позволяет динамически управлять поведением:

useQuery({
  queryKey: ['metrics'],
  queryFn: fetchMetrics,
  refetchInterval: (data) => {
    if (!data) return false
    if (data.status === 'paused') return false
    return 5000
  }
})

Здесь обновление отключается при отсутствии данных или при определённом статусе, иначе выполняется каждые 5 секунд.

Прекращение обновлений

Возврат false полностью отключает периодическое обновление. Это полезно для экономии ресурсов при отсутствии необходимости в актуализации данных.

refetchInterval: false

Также важно понимать, что установка 0 не используется как валидное значение интервала. Для отключения всегда применяется false.

Влияние активности вкладки

TanStack Query по умолчанию учитывает активность окна браузера. При уходе пользователя со страницы поведение может изменяться через refetchIntervalInBackground.

useQuery({
  queryKey: ['notifications'],
  queryFn: fetchNotifications,
  refetchInterval: 3000,
  refetchIntervalInBackground: true
})

При значении true обновление продолжается даже в неактивной вкладке. При false таймер приостанавливается до возвращения фокуса.

Сочетание с фокусом окна

Периодическое обновление работает совместно с механизмом refetch при возвращении фокуса (refetchOnWindowFocus). В результате данные могут обновляться как по таймеру, так и при активизации окна.

Это может привести к избыточным запросам, если оба механизма включены одновременно без ограничений.

useQuery({
  queryKey: ['profile'],
  queryFn: fetchProfile,
  refetchInterval: 10000,
  refetchOnWindowFocus: true
})

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

Управление через состояние запроса

Интервальное обновление может зависеть от состояния запроса:

  • isFetching
  • isPaused
  • status

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

useQuery({
  queryKey: ['feed'],
  queryFn: fetchFeed,
  refetchInterval: (data, query) => {
    if (query.state.isFetching) return false
    return 5000
  }
})

Такой подход предотвращает наложение запросов друг на друга.

Динамическое изменение интервала

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

useQuery({
  queryKey: ['live-score'],
  queryFn: fetchScore,
  refetchInterval: (data) => {
    if (!data) return 10000
    if (data.status === 'live') return 2000
    if (data.status === 'finished') return false
    return 10000
  }
})

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

Влияние staleTime на периодическое обновление

staleTime определяет, как долго данные считаются свежими. Однако он не блокирует refetchInterval.

useQuery({
  queryKey: ['products'],
  queryFn: fetchProducts,
  staleTime: 30000,
  refetchInterval: 5000
})

Даже если данные ещё «свежие», периодическое обновление продолжает выполняться. Это важное отличие от ручных инвалидизаций, которые учитывают stale-логику.

Оптимизация нагрузки при частых обновлениях

Частые интервалы могут привести к избыточным запросам. Для контроля нагрузки используются несколько стратегий.

Условное отключение при ошибках

useQuery({
  queryKey: ['status'],
  queryFn: fetchStatus,
  retry: 3,
  refetchInterval: (data, query) => {
    if (query.state.error) return false
    return 5000
  }
})

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

Комбинация с enabled

useQuery({
  queryKey: ['stream'],
  queryFn: fetchStream,
  enabled: isStreaming,
  refetchInterval: 3000
})

Если enabled = false, запрос не выполняется вообще, включая интервальные обновления.

Различие между refetchInterval и polling

Периодическое обновление в TanStack Query часто называют polling, но реализация отличается от классического подхода:

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

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

Очистка и управление жизненным циклом

При размонтировании компонента интервал автоматически прекращается. Дополнительных действий не требуется. Однако при использовании глобальных настроек QueryClient можно задать поведение по умолчанию:

const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      refetchInterval: 10000
    }
  }
})

Это применяет периодическое обновление ко всем запросам, если оно не переопределено локально.

Практические сценарии применения

Периодическое обновление наиболее эффективно в следующих случаях:

  • мониторинг серверных метрик
  • обновление очередей задач
  • ленты уведомлений
  • статусные панели
  • live-данные (спорт, финансы, трекинг)

В статических интерфейсах или CRUD-страницах использование интервалов часто приводит к лишним нагрузкам и ухудшению производительности.

Поведение при повторных монтированиях

При повторном монтировании компонента интервал восстанавливается автоматически на основе текущего состояния кэша. Если данные уже существуют, запрос может быть пропущен до наступления условий staleTime или refetchInterval.

Это позволяет избегать «дребезга» запросов при частых переходах между экранами.

Итоговая модель работы интервала

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

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

Эта комбинация делает polling частью реактивной модели данных, а не внешним побочным процессом, как в традиционных реализациях через setInterval