Polling (периодическое опросное обновление данных) в TanStack Query представляет собой механизм автоматического повторного запроса к серверу через заданные интервалы времени. Этот подход используется в сценариях, где данные изменяются регулярно и требуется поддерживать интерфейс в актуальном состоянии без ручного обновления страницы или действий пользователя.
В отличие от событийных моделей (WebSocket, Server-Sent Events), polling основан на циклическом выполнении запросов и полностью управляется клиентской логикой TanStack Query через конфигурацию query.
Основной инструмент для реализации polling — параметр
refetchInterval. Он задаёт интервал в миллисекундах, через
который запрос будет автоматически повторяться.
import { useQuery } from '@tanstack/react-query'
function useNotifications() {
return useQuery({
queryKey: ['notifications'],
queryFn: fetchNotifications,
refetchInterval: 5000
})
}
В данном случае запрос fetchNotifications будет
выполняться каждые 5 секунд, пока компонент, использующий query,
находится в активном состоянии.
Ключевая особенность поведения:
refetchInterval может быть функцией, что позволяет
управлять polling динамически, учитывая состояние данных или
приложения.
useQuery({
queryKey: ['orders'],
queryFn: fetchOrders,
refetchInterval: (data) => {
if (!data) return 1000
if (data.status === 'processing') return 2000
if (data.status === 'completed') return false
return 5000
}
})
Логика:
Возврат false отключает автоматическое обновление.
Polling может быть зависим от внешних условий. Параметр
enabled управляет активацией запроса целиком, включая его
автоматическое повторение.
useQuery({
queryKey: ['messages', chatId],
queryFn: () => fetchMessages(chatId),
enabled: !!chatId,
refetchInterval: 3000
})
Если chatId отсутствует, запрос полностью
деактивируется, включая polling.
TanStack Query по умолчанию интегрирует refetch при возврате фокуса окна. Это влияет на polling, так как может приводить к дополнительным запросам.
Поведение контролируется через:
refetchOnWindowFocusconst queryClient = new QueryClient({
defaultOptions: {
queries: {
refetchOnWindowFocus: true
}
}
})
При включённом polling и активном refetch on focus возможны «всплески» запросов при переключении вкладок.
По умолчанию TanStack Query приостанавливает polling, когда вкладка находится в фоне. Это оптимизация для экономии ресурсов.
Поведение управляется параметром:
useQuery({
queryKey: ['prices'],
queryFn: fetchPrices,
refetchInterval: 2000,
refetchIntervalInBackground: true
})
Если значение true, polling продолжается даже при
неактивной вкладке.
Сценарии использования:
Сценарии, где лучше оставить false:
staleTime влияет на то, считается ли данные устаревшими,
но не отключает polling напрямую. Однако он меняет поведение refetch при
монтировании и фокусе.
useQuery({
queryKey: ['profile'],
queryFn: fetchProfile,
staleTime: 10000,
refetchInterval: 3000
})
Даже если данные считаются свежими в рамках staleTime,
polling продолжает выполняться.
Разделение логики:
staleTime управляет «свежестью» данныхrefetchInterval управляет циклом обновленияPolling может пересекаться с мутациями (useMutation),
что приводит к потенциальным гонкам данных.
Типичный сценарий:
Для минимизации конфликтов используются:
queryClient.invalidateQueriesПример отключения polling на время мутации:
const query = useQuery({
queryKey: ['tasks'],
queryFn: fetchTasks,
refetchInterval: 3000
})
const mutation = useMutation({
mutationFn: updateTask,
onMutate: async () => {
await queryClient.cancelQueries(['tasks'])
},
onSettled: () => {
queryClient.invalidateQueries(['tasks'])
}
})
Функциональная форма refetchInterval позволяет учитывать
не только данные, но и состояние query.
useQuery({
queryKey: ['sync'],
queryFn: fetchSyncState,
refetchInterval: (data, query) => {
if (query.state.status === 'error') return 1000
if (query.state.fetchStatus === 'fetching') return false
return 5000
}
})
Здесь учитываются:
Polling можно полностью отключить несколькими способами:
useQuery({
queryKey: ['logs'],
queryFn: fetchLogs,
refetchInterval: false
})
Или динамически:
refetchInterval: shouldPoll ? 2000 : false
Также отключение возможно через:
enabled: falseTanStack Query учитывает состояние сети браузера. При потере соединения polling автоматически приостанавливается.
После восстановления:
useQuery({
queryKey: ['dashboard'],
queryFn: fetchDashboard,
refetchInterval: 4000,
networkMode: 'online'
})
Режимы:
online — запросы только при активной сетиalways — попытка выполнения даже без сети (с fallback
логикой)offlineFirst — приоритет локального кешаПри масштабировании системы с множеством polling-запросов возникают проблемы производительности:
Подходы оптимизации:
staleTimerefetchIntervalenabled)Пример адаптивного polling:
useQuery({
queryKey: ['metrics'],
queryFn: fetchMetrics,
refetchInterval: (data) => {
if (!data) return 1000
return data.load > 80 ? 2000 : 10000
}
})
TanStack Query использует кеш как базовый слой, а polling обновляет его инкрементально.
Сценарий:
Это позволяет: