Skip to main content
The QueryObserver is the underlying mechanism that powers hooks like useQuery. It subscribes to a query and notifies listeners when the query state changes.

Constructor

Creates a new QueryObserver instance.
const observer = new QueryObserver<TQueryFnData, TError, TData, TQueryData, TQueryKey>(
  client: QueryClient,
  options: QueryObserverOptions<TQueryFnData, TError, TData, TQueryData, TQueryKey>
)
client
QueryClient
required
The QueryClient instance to use.
options
QueryObserverOptions
required
Options for the observer.

Example

import { QueryObserver } from '@tanstack/query-core'

const observer = new QueryObserver(queryClient, {
  queryKey: ['todos'],
  queryFn: fetchTodos,
  staleTime: 5000,
})

Methods

subscribe

Subscribes to the observer and receives updates when the query state changes.
subscribe(listener: (result: QueryObserverResult<TData, TError>) => void): () => void
listener
(result: QueryObserverResult<TData, TError>) => void
required
Function called when the query result changes.
() => void
function
Returns an unsubscribe function.

Example

const unsubscribe = observer.subscribe((result) => {
  console.log('Query result:', result.data)
  console.log('Is loading:', result.isLoading)
  console.log('Is error:', result.isError)
})

// Later, unsubscribe
unsubscribe()

setOptions

Updates the observer options. This will trigger a re-evaluation of the query.
setOptions(
  options: QueryObserverOptions<TQueryFnData, TError, TData, TQueryData, TQueryKey>
): void
options
QueryObserverOptions
required
New options for the observer.

Example

observer.setOptions({
  queryKey: ['todos'],
  queryFn: fetchTodos,
  staleTime: 10000, // Update staleTime
})

getCurrentResult

Returns the current result of the query.
getCurrentResult(): QueryObserverResult<TData, TError>
QueryObserverResult
QueryObserverResult
Returns the current query result.

Example

const result = observer.getCurrentResult()
console.log(result.data)

getCurrentQuery

Returns the current Query instance being observed.
getCurrentQuery(): Query<TQueryFnData, TError, TQueryData, TQueryKey>
Query
Query
Returns the Query instance.

getOptimisticResult

Returns an optimistic result based on the provided options without subscribing.
getOptimisticResult(
  options: DefaultedQueryObserverOptions<TQueryFnData, TError, TData, TQueryData, TQueryKey>
): QueryObserverResult<TData, TError>
options
DefaultedQueryObserverOptions
required
Options to compute the optimistic result.
QueryObserverResult
QueryObserverResult
Returns an optimistic query result.

refetch

Manually refetches the query.
refetch(options?: RefetchOptions): Promise<QueryObserverResult<TData, TError>>
options
RefetchOptions
Options for refetching.
Promise<QueryObserverResult>
Promise
Returns a promise that resolves with the query result.

Example

const result = await observer.refetch()
console.log('Refetched data:', result.data)

fetchOptimistic

Fetches the query with the provided options and returns the result.
fetchOptimistic(
  options: QueryObserverOptions<TQueryFnData, TError, TData, TQueryData, TQueryKey>
): Promise<QueryObserverResult<TData, TError>>
options
QueryObserverOptions
required
Options for the fetch.
Promise<QueryObserverResult>
Promise
Returns a promise that resolves with the query result.

destroy

Destroys the observer and cleans up all subscriptions and timers.
destroy(): void

Example

observer.destroy()

trackResult

Returns a proxied version of the result that tracks which properties are accessed.
trackResult(
  result: QueryObserverResult<TData, TError>,
  onPropTracked?: (key: keyof QueryObserverResult) => void
): QueryObserverResult<TData, TError>
result
QueryObserverResult
required
The result to track.
onPropTracked
(key: keyof QueryObserverResult) => void
Callback called when a property is accessed.
QueryObserverResult
QueryObserverResult
Returns a proxied result that tracks property access.

trackProp

Manually track a specific property.
trackProp(key: keyof QueryObserverResult): void
key
keyof QueryObserverResult
required
The property key to track.

Lifecycle

When you subscribe to a QueryObserver:
  1. The observer adds itself to the query’s list of observers
  2. If needed, the query will fetch data on mount
  3. The observer sets up stale and refetch interval timers
  4. When the query state changes, the observer notifies all listeners
  5. When you unsubscribe, the observer cleans up timers and removes itself from the query

Usage Example

Here’s a complete example showing how to use QueryObserver:
import { QueryClient, QueryObserver } from '@tanstack/query-core'

// Create client
const queryClient = new QueryClient()

// Create observer
const observer = new QueryObserver(queryClient, {
  queryKey: ['todos'],
  queryFn: async () => {
    const response = await fetch('/api/todos')
    return response.json()
  },
  staleTime: 5000,
})

// Subscribe to changes
const unsubscribe = observer.subscribe((result) => {
  if (result.isLoading) {
    console.log('Loading...')
  } else if (result.isError) {
    console.error('Error:', result.error)
  } else if (result.isSuccess) {
    console.log('Data:', result.data)
  }
})

// Later, update options
observer.setOptions({
  queryKey: ['todos'],
  queryFn: fetchTodos,
  staleTime: 10000,
})

// Cleanup when done
unsubscribe()
observer.destroy()

Internal Methods

The following methods are used internally and are not typically needed:

shouldFetchOnReconnect

Determines if the query should refetch when reconnecting.
shouldFetchOnReconnect(): boolean

shouldFetchOnWindowFocus

Determines if the query should refetch when the window regains focus.
shouldFetchOnWindowFocus(): boolean

updateResult

Updates the current result and notifies listeners if changed.
protected updateResult(): void

onQueryUpdate

Called when the query is updated.
onQueryUpdate(): void

Build docs developers (and LLMs) love