SuperAPI AI Directory

tanstack-query-intent-core-fetch-and-observe-queries

Coding & development

View repository

Updated 10-16 00:02

About this skill

Setup

import { useQuery } from '@tanstack/react-query'

export function Todos() {
  const query = useQuery({
    queryKey: ['todos'],
    queryFn: async () => [{ id: 1, title: 'Ship' }],
  })

  if (query.isPending) return <p>Loading</p>
  if (query.isError) return <p>{query.error.message}</p>
  return <pre>{JSON.stringify(query.data)}</pre>
}

Core Patterns

Fetch imperatively through QueryClient

import { QueryClient } from '@tanstack/react-query'

const queryClient = new QueryClient()

export function loadTodo(todoId: string) {
  return queryClient.fetchQuery({
    queryKey: ['todo', todoId],
    queryFn: async () => ({ id: todoId }),
  })
}

Ensure cached data for loaders

import { QueryClient } from '@tanstack/react-query'

const queryClient = new QueryClient()

export function ensureTodos() {
  return queryClient.ensureQueryData({
    queryKey: ['todos'],
    queryFn: async () => [{ id: 1 }],
  })
}

Distinguish status from fetchStatus

import { useQuery } from '@tanstack/react-query'

export function TodoCount() {
  const query = useQuery({
    queryKey: ['todos'],
    queryFn: async () => [{ id: 1 }],
  })
  const label =
    query.fetchStatus === 'fetching' && query.status === 'success'
      ? 'Refreshing'
      : 'Ready'
  return (
    <p>
      {query.data?.length ?? 0} {label}
    </p>
  )
}

Common Mistakes

CRITICAL Void query function

Wrong:

import { useQuery } from '@tanstack/react-query'

export function useTodos() {
  return useQuery({
    queryKey: ['todos'],
    queryFn: async () => {
      await Promise.resolve([{ id: 1 }])
    },
  })
}

Correct:

import { useQuery } from '@tanstack/react-query'

export function useTodos() {
  return useQuery({
    queryKey: ['todos'],
    queryFn: async () => Promise.resolve([{ id: 1 }]),
  })
}

Query functions must return data; a missing return caches undefined.

Source: TanStack/query:docs/eslint/no-void-query-fn.md

HIGH Only checking pending offline

Wrong:

import { useQuery } from '@tanstack/react-query'

export function Todos() {
  const query = useQuery({
    queryKey: ['todos'],
    queryFn: async () => [{ id: 1 }],
    networkMode: 'online',
  })
  return query.isPending ? <p>Loading</p> : <p>{query.fetchStatus}</p>
}

Correct:

import { useQuery } from '@tanstack/react-query'

export function Todos() {
  const query = useQuery({
    queryKey: ['todos'],
    queryFn: async () => [{ id: 1 }],
    networkMode: 'online',
  })
  return query.fetchStatus === 'paused' ? <p>Offline</p> : <p>{query.status}</p>
}

status describes data state; fetchStatus describes whether fetching is paused, fetching, or idle.

Source: TanStack/query:docs/framework/react/guides/queries.md

HIGH Using queries for writes

Wrong:

import { useQuery } from '@tanstack/react-query'

export function useSaveTodo(title: string) {
  return useQuery({
    queryKey: ['saveTodo', title],
    queryFn: async () => ({ id: 1, title }),
  })
}

Correct:

import { useMutation } from '@tanstack/react-query'

export function useSaveTodo() {
  return useMutation({
    mutationFn: async (title: string) => ({ id: 1, title }),
  })
}

Queries are for reads; writes need mutation lifecycle hooks, invalidation, rollback, and mutation state.

Source: TanStack/query:docs/framework/react/guides/mutations.md

See also: core/tune-defaults-freshness-retries-and-refetching for how defaults change status behavior.