SuperAPI AI Directory

tanstack-query-intent-core-understand-query-internals-a-8ab976f4

Testing & quality

View repository

Updated 10-16 00:02

About this skill

Mental Model

QueryClient owns the caches. QueryCache stores Query instances. Hooks and adapter APIs create QueryObserver instances that subscribe components to one query. Observer-level options like select, staleTime, polling, and tracked result access shape what each component sees.

An inactive query can exist in the cache without active observers. It can be read imperatively, hydrated, invalidated, or garbage collected, but it is not the same as a component actively observing query state.

Core Patterns

Use observers for UI reads

function TodoPage({ id }: { id: string }) {
  const todo = useQuery({
    queryKey: ['todo', id],
    queryFn: () => fetchTodo(id),
  })

if (todo.isPending) return Loading... if (todo.isError) return {todo.error.message} return {todo.data.title} }


### Use QueryClient for cache orchestration

```ts
await queryClient.ensureQueryData(todoOptions(id))
queryClient.invalidateQueries({ queryKey: ['todo', id] })
queryClient.setQueryData(['todo', id], (old) => old && { ...old, title })

Common Mistakes

HIGH Treating cache presence as active usage

Wrong:

const todo = queryClient.getQueryData(['todo', id])
return <TodoView todo={todo} />

Correct:

const todo = useQuery(todoOptions(id))
return <TodoView todo={todo.data} />

UI reads should create observers so invalidation, refetch triggers, stale status, and garbage collection behave as expected.

Source: https://tkdodo.eu/blog/inside-react-query

MEDIUM Expecting one query to have one option set

Wrong:

// assume staleTime is stored only on the Query
queryClient.getQueryCache().find({ queryKey })?.options.staleTime

Correct:

const query = queryClient.getQueryCache().find({ queryKey })
const observerStaleTimes = query?.observers.map(
  (observer) => observer.options.staleTime,
)

Several options are observer-level, so multiple components can observe the same query with different selectors or freshness behavior.

Source: https://tkdodo.eu/blog/automatic-query-invalidation-after-mutations

MEDIUM Debugging without checking observer count

Wrong:

queryClient.invalidateQueries({ queryKey: ['todos'] })
// expect every cached todo query to refetch immediately

Correct:

queryClient.invalidateQueries({ queryKey: ['todos'], refetchType: 'active' })

Inactive queries are not automatically the same as mounted queries. Check observer count in devtools when invalidation or garbage collection looks surprising.

Source: https://tkdodo.eu/blog/inside-react-query