SuperAPI AI Directory

tanstack-query-intent-core-coordinate-query-execution

General & other

View repository

Updated 10-16 00:02

About this skill

Setup

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

export function Projects(props: { userId?: string }) {
  const projects = useQuery({
    queryKey: ['projects', props.userId],
    queryFn: async () => [{ id: 'p1', userId: props.userId }],
    enabled: Boolean(props.userId),
  })

  return <pre>{JSON.stringify(projects.data ?? [])}</pre>
}

Core Patterns

Gate by dependency

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

export function useUserProjects(userId: string | undefined) {
  return useQuery({
    queryKey: ['projects', userId],
    queryFn: async () => [{ id: 'p1', userId }],
    enabled: userId !== undefined,
  })
}

Run dynamic parallel queries

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

export function useMessages(ids: Array<string>) {
  return useQueries({
    queries: ids.map((id) => ({
      queryKey: ['message', id],
      queryFn: async () => ({ id, text: 'Hello' }),
    })),
  })
}

Show background refresh separately

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

export function GlobalRefreshIndicator() {
  const count = useIsFetching()
  return count > 0 ? <p>Refreshing</p> : null
}

Common Mistakes

HIGH Imperative disabled query

Wrong:

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

export function useSearch(term: string) {
  return useQuery({
    queryKey: ['search'],
    queryFn: async () => [term],
    enabled: false,
  })
}

Correct:

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

export function useSearch(term: string) {
  return useQuery({
    queryKey: ['search', term],
    queryFn: async () => [term],
    enabled: term.length > 0,
  })
}

Permanent disabling opts out of normal invalidation and dependency-driven cache behavior.

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

HIGH Duplicate useQueries keys

Wrong:

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

export function useUsers(ids: Array<string>) {
  return useQueries({
    queries: ids.map((id) => ({
      queryKey: ['user'],
      queryFn: async () => ({ id }),
    })),
  })
}

Correct:

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

export function useUsers(ids: Array<string>) {
  return useQueries({
    queries: ids.map((id) => ({
      queryKey: ['user', id],
      queryFn: async () => ({ id }),
    })),
  })
}

Duplicate keys can share placeholder, selected, or cached data between different items.

Source: TanStack/query:docs/framework/react/reference/useQueries.md

MEDIUM Full-page spinner on background refetch

Wrong:

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

export function Todos() {
  const query = useQuery({
    queryKey: ['todos'],
    queryFn: async () => [{ id: 1 }],
  })
  return query.isFetching ? (
    <p>Loading</p>
  ) : (
    <pre>{JSON.stringify(query.data)}</pre>
  )
}

Correct:

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

export function Todos() {
  const query = useQuery({
    queryKey: ['todos'],
    queryFn: async () => [{ id: 1 }],
  })
  return (
    <pre>
      {query.isFetching ? 'Refreshing ' : ''}
      {JSON.stringify(query.data ?? [])}
    </pre>
  )
}

isFetching also covers background refreshes after data is already available.

Source: TanStack/query:docs/framework/react/guides/background-fetching-indicators.md