Периодическое обновление данных в 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
})
В таких сценариях важно учитывать нагрузку и возможные дублирующие запросы.
Интервальное обновление может зависеть от состояния запроса:
isFetchingisPausedstatusПример отключения интервала во время активного запроса:
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 определяет, как долго данные считаются
свежими. Однако он не блокирует 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
}
})
При ошибке запросы прекращаются до ручного вмешательства.
useQuery({
queryKey: ['stream'],
queryFn: fetchStream,
enabled: isStreaming,
refetchInterval: 3000
})
Если enabled = false, запрос не выполняется вообще,
включая интервальные обновления.
Периодическое обновление в TanStack Query часто называют polling, но реализация отличается от классического подхода:
Это делает механизм более устойчивым к гонкам и утечкам памяти.
При размонтировании компонента интервал автоматически прекращается. Дополнительных действий не требуется. Однако при использовании глобальных настроек QueryClient можно задать поведение по умолчанию:
const queryClient = new QueryClient({
defaultOptions: {
queries: {
refetchInterval: 10000
}
}
})
Это применяет периодическое обновление ко всем запросам, если оно не переопределено локально.
Периодическое обновление наиболее эффективно в следующих случаях:
В статических интерфейсах или CRUD-страницах использование интервалов часто приводит к лишним нагрузкам и ухудшению производительности.
При повторном монтировании компонента интервал восстанавливается автоматически на основе текущего состояния кэша. Если данные уже существуют, запрос может быть пропущен до наступления условий staleTime или refetchInterval.
Это позволяет избегать «дребезга» запросов при частых переходах между экранами.
Механизм периодического обновления в TanStack Query можно рассматривать как слой поверх кэша, который:
Эта комбинация делает polling частью реактивной модели данных, а не внешним побочным процессом, как в традиционных реализациях через setInterval