- Important Defaults
- Queries
- Query Keys
- Query Functions
- Query Options
- Network Mode
- Parallel Queries
- Dependent Queries
- Background Fetching Indicators
- Window Focus Refetching
- Polling
- Disabling/Pausing Queries
- Query Retries
- Paginated Queries
- Infinite Queries
- Initial Query Data
- Placeholder Query Data
- Mutations
- Query Invalidation
- Invalidation from Mutations
- Updates from Mutation Responses
- Optimistic Updates
- Query Cancellation
- Scroll Restoration
- Filters
- Prefetching
- SSR & Nuxt
- Caching
- Default Query Fn
- Suspense
- Testing
- Custom Client
- Does this replace [Vuex, Pinia]?
- Migrating to v5
Polling
refetchInterval makes a query refetch on a timer. Set it to a number in milliseconds and the query runs every N ms while there's at least one active observer:
useQuery({
queryKey: ['prices'],
queryFn: fetchPrices,
refetchInterval: 5_000, // every 5 seconds
})Polling is independent of staleTime. A query can be fresh and still poll on schedule; see Important Defaults for how staleTime interacts with other refetch behaviors. refetchInterval fires on its own clock regardless of freshness.
Adapting the interval to query state#
Pass a function instead of a number to compute the interval from the current query. The function receives the Query object and should return a number in ms or false to stop polling:
useQuery({
queryKey: ['job', jobId],
queryFn: () => fetchJobStatus(jobId),
refetchInterval: (query) => {
// Stop polling once the job finishes
if (query.state.data?.status === 'complete') return false
return 2_000
},
})Returning false clears the interval timer. If the query result changes so the function would return a positive number again, polling resumes automatically.
Background polling#
By default, polling pauses when the browser tab loses focus. For dashboards or any interface where data needs to stay current even while the user is in another tab, disable that behavior:
useQuery({
queryKey: ['portfolio'],
queryFn: fetchPortfolio,
refetchInterval: 30_000,
refetchIntervalInBackground: true,
})Pausing polling#
Pass a function to refetchInterval and close over component state to control when polling runs:
useQuery({
queryKey: ['prices', tokenAddress],
queryFn: () => fetchPrice(tokenAddress),
refetchInterval: () => {
if (!tokenAddress || isPaused) return false
return 15_000
},
})Polling with offline support#
TanStack Query detects connectivity by listening to the browser's online and offline events. In environments where those events don't fire reliably (Electron, some embedded WebViews), set networkMode: 'always' to skip the connectivity check:
useQuery({
queryKey: ['chainStatus'],
queryFn: fetchChainStatus,
refetchInterval: 10_000,
networkMode: 'always',
})For more on network modes, see Network Mode.
Note on deduplication#
Each QueryObserver (each component using useQuery with refetchInterval) runs its own timer. Two components subscribed to the same key with refetchInterval: 5000 each fire their timer every 5 seconds. What gets deduplicated is concurrent in-flight fetches: if two timers fire at the same time, only one network request goes out. The timers are observer-level; the deduplication is query-level.