Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions packages/query-core/src/__tests__/queryObserver.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
} from 'vitest'
import { queryKey, sleep } from '@tanstack/query-test-utils'
import { QueryClient, QueryObserver, focusManager } from '..'
import { setIsServer } from './utils'
import type { QueryObserverResult } from '..'

describe('queryObserver', () => {
Expand Down Expand Up @@ -867,6 +868,57 @@ describe('queryObserver', () => {
focusManager.setFocused(true)
})

test('should not refetch on server by default', async () => {
const restoreIsServer = setIsServer(true)

const key = queryKey()
let count = 0

const observer = new QueryObserver(queryClient, {
queryKey: key,
queryFn: () => {
count++
return Promise.resolve('data')
},
refetchInterval: 10,
})

const unsubscribe = observer.subscribe(() => undefined)
await vi.advanceTimersByTimeAsync(30)

// Should only have the initial fetch, no refetch interval
expect(count).toBe(1)

unsubscribe()
restoreIsServer()
})

test('should refetch on server when refetchIntervalOnServer is true', async () => {
const restoreIsServer = setIsServer(true)

const key = queryKey()
let count = 0

const observer = new QueryObserver(queryClient, {
queryKey: key,
queryFn: () => {
count++
return Promise.resolve('data')
},
refetchInterval: 10,
refetchIntervalOnServer: true,
})

const unsubscribe = observer.subscribe(() => undefined)
await vi.advanceTimersByTimeAsync(30)

// Should have the initial fetch plus refetches from the interval
expect(count).toBeGreaterThan(1)

unsubscribe()
restoreIsServer()
})

test('should not use replaceEqualDeep for select value when structuralSharing option is true', async () => {
const key = queryKey()

Expand Down
2 changes: 1 addition & 1 deletion packages/query-core/src/queryObserver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,7 @@ export class QueryObserver<
this.#currentRefetchInterval = nextInterval

if (
isServer ||
(isServer && !this.options.refetchIntervalOnServer) ||
resolveEnabled(this.options.enabled, this.#currentQuery) === false ||
!isValidTimeout(this.#currentRefetchInterval) ||
this.#currentRefetchInterval === 0
Expand Down
12 changes: 12 additions & 0 deletions packages/query-core/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,18 @@ export interface QueryObserverOptions<
* Defaults to `false`.
*/
refetchIntervalInBackground?: boolean
/**
* If set to `true`, the refetch interval will be active even in server environments
* (where `typeof window === 'undefined'`).
*
* By default, `refetchInterval` is paused on the server because most server-side
* rendering scenarios don't need polling. However, long-running server processes
* (like daemons or background workers) that use TanStack Query for data synchronization
* may need polling to function correctly.
*
* Defaults to `false`.
*/
refetchIntervalOnServer?: boolean
/**
* If set to `true`, the query will refetch on window focus if the data is stale.
* If set to `false`, the query will not refetch on window focus.
Expand Down
Loading