Receber por email
← Voltar para o catálogo

tanstack-query

This skill provides comprehensive knowledge for TanStack Query v5 (React Query) server state management in React applications. It should be used when setting up data fetching with useQuery, implementing mutations with useMutation, configuring QueryClient, managing caching strategies, migrating from v4 to v5, implementing optimistic updates, using infinite queries, or encountering query/mutation er

15estrelas
Atualizado há 11 meses

Ver no GitHub ↗ Licença: MIT

Como adicionar

/plugin marketplace add jackspace/ClaudeSkillz

O comando exato pode variar conforme o repositório. Confira o README no GitHub.

Para o autor da skill

Cole no README do seu repo

Mostra que sua skill está catalogada na Skillteca, gera backlink e tráfego rastreável.

[![Skillteca](https://www.skillteca.com.br/api/badge/tanstack-query/svg)](https://www.skillteca.com.br/skills/tanstack-query)

Skills relacionadas

Ver todas de Dados e Análise →

Alerta por categoria

Receba novas skills de Dados e Análise toda segunda

1 email curto, só com as skills novas de Dados e Análise. 4 minutos de leitura, sem spam, cancela com 1 clique.

Você confirma o email no primeiro envio. Sem spam. Cancela com 1 clique.

Ler descrição completa

TanStack Query (React Query) v5

Status: Production Ready ✅ Last Updated: 2025-10-22 Dependencies: React 18.0+, TypeScript 4.7+ (recommended) Latest Versions: @tanstack/react-query@5.90.5, @tanstack/react-query-devtools@5.90.2

Quick Start (5 Minutes)

1. Install Dependencies

npm install @tanstack/react-query@latest
npm install -D @tanstack/react-query-devtools@latest

Why this matters:

  • TanStack Query v5 requires React 18+ (uses useSyncExternalStore)
  • DevTools are essential for debugging queries and mutations
  • v5 has breaking changes from v4 - use latest for all fixes

2. Set Up QueryClient Provider

// src/main.tsx or src/index.tsx
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { ReactQueryDevtools } from '@tanstack/react-query-devtools'
import App from './App'

// Create a client
const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      staleTime: 1000 * 60 * 5, // 5 minutes
      gcTime: 1000 * 60 * 60, // 1 hour (formerly cacheTime)
      retry: 1,
      refetchOnWindowFocus: false,
    },
  },
})

createRoot(document.getElementById('root')!).render(
  <StrictMode>
    <QueryClientProvider client={queryClient}>
      <App />
      <ReactQueryDevtools initialIsOpen={false} />
    </QueryClientProvider>
  </StrictMode>
)

CRITICAL:

  • Wrap entire app with QueryClientProvider
  • Configure staleTime to avoid excessive refetches (default is 0)
  • Use gcTime (not cacheTime - renamed in v5)
  • DevTools should be inside provider

3. Create First Query

// src/hooks/useTodos.ts
import { useQuery } from '@tanstack/react-query'

type Todo = {
  id: number
  title: string
  completed: boolean
}

async function fetchTodos(): Promise<Todo[]> {
  const response = await fetch('/api/todos')
  if (!response.ok) {
    throw new Error('Failed to fetch todos')
  }
  return response.json()
}

export function useTodos() {
  return useQuery({
    queryKey: ['todos'],
    queryFn: fetchTodos,
  })
}

// Usage in component:
function TodoList() {
  const { data, isPending, isError, error } = useTodos()

  if (isPending) return <div>Loading...</div>
  if (isError) return <div>Error: {error.message}</div>

  return (
    <ul>
      {data.map(todo => (
        <li key={todo.id}>{todo.title}</li>
      ))}
    </ul>
  )
}

CRITICAL:

  • v5 requires object syntax: useQuery({ queryKey, queryFn })
  • Use isPending (not isLoading - that now means "pending AND fetching")
  • Always throw errors in queryFn for proper error handling
  • QueryKey should be array for consistent cache keys

4. Create First Mutation

// src/hooks/useAddTodo.ts
import { useMutation, useQueryClient } from '@tanstack/react-query'

type NewTodo = {
  title: string
}

async function addTodo(newTodo: NewTodo) {
  const response = await fetch('/api/todos', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(newTodo),
  })
  if (!response.ok) throw new Error('Failed to add todo')
  return response.json()
}

export function useAddTodo() {
  const queryClient = useQueryClient()

  return useMutation({
    mutationFn: addTodo,
    onSuccess: () => {
      // Invalidate and refetch todos
      queryClient.invalidateQueries({ queryKey: ['todos'] })
    },
  })
}

// Usage in component:
function AddTodoForm() {
  const { mutate, isPending } = useAddTodo()

  const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
    e.preventDefault()
    const formData = new FormData(e.currentTarget)
    mutate({ title: formData.get('title') as string })
  }

  return (
    <form onSubmit={handleSubmit}>
      <input name="title" required />
      <button type="submit" disabled={isPending}>
        {isPending ? 'Adding...' : 'Add Todo'}
      </button>
    </form>
  )
}

Why this works:

  • Mutations use callbacks (onSuccess, onError, onSettled) - queries don't
  • invalidateQueries triggers background refetch
  • Mutations don't cache by default (correct behavior)

The 7-Step Setup Process

Step 1: Install Dependencies

# Core library (required)
npm install @tanstack/react-query

# DevTools (highly recommended for development)
npm install -D @tanstack/react-query-devtools

# Optional: ESLint plugin for best practices
npm install -D @tanstack/eslint-plugin-query

Package roles:

  • @tanstack/react-query - Core React hooks and QueryClient
  • @tanstack/react-query-devtools - Visual debugger (dev only, tree-shakeable)
  • @tanstack/eslint-plugin-query - Catches common mistakes

Version requirements:

  • React 18.0 or higher (uses useSyncExternalStore)
  • TypeScript 4.7+ for best type inference (optional but recommended)

Step 2: Configure QueryClient

// src/lib/query-client.ts
import { QueryClient } from '@tanstack/react-query'

export const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      // How long data is considered fresh (won't refetch during this time)
      staleTime: 1000 * 60 * 5, // 5 minutes

      // How long inactive data stays in cache before garbage collection
      gcTime: 1000 * 60 * 60, // 1 hour (v5: renamed from cacheTime)

      // Retry failed requests (0 on server, 3 on client by default)
      retry: (failureCount, error) => {
        if (error instanceof Response && error.status === 404) return false
        return failureCount < 3
      },

      // Refetch on window focus (can be annoying during dev)
      refetchOnWindowFocus: false,

      // Refetch on network reconnect
      refetchOnReconnect: true,

      // Refetch on component mount if data is stale
      refetchOnMount: true,
    },
    mutations: {
      // Retry mutations on failure (usually don't want this)
      retry: 0,
    },
  },
})

Key configuration decisions:

staleTime vs gcTime:

  • staleTime: How long until data is considered "stale" and might refetch
  • 0 (default): Data is immediately stale, refetches on mount/focus
  • 1000 60 5: Data fresh for 5 min, no refetch during this time
  • Infinity: Data never stale, manual invalidation only
  • gcTime: How long unused data stays in cache
  • 1000 60 5 (default): 5 minutes
  • Infinity: Never garbage collect (memory leak risk)

When to refetch:

  • refetchOnWindowFocus: true - Good for frequently changing data (stock prices)
  • refetchOnWindowFocus: false - Good for stable data or during development
  • refetchOnMount: true - Ensures fresh data when component mounts
  • refetchOnReconnect: true - Refetch after network reconnect

Step 3: Wrap App with Provider

// src/main.tsx
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import { QueryClientProvider } from '@tanstack/react-query'
import { ReactQueryDevtools } from '@tanstack/react-query-devtools'
import { queryClient } from './lib/query-client'
import App from './App'

createRoot(document.getElementById('root')!).render(
  <StrictMode>
    <QueryClientProvider client={queryClient}>
      <App />
      <ReactQueryDevtools
        initialIsOpen={false}
        buttonPosition="bottom-right"
      />
    </QueryClientProvider>
  </StrictMode>
)

Provider placement:

  • Must wrap all components that use TanStack Query hooks
  • DevTools must be inside provider
  • Only one QueryClient instance for entire app

DevTools configuration:

  • initialIsOpen={false} - Collapsed by default
  • buttonPosition="bottom-right" - Where to show toggle button
  • Automatically removed in production builds (tree-shaken)

Step 4: Create Custom Query Hooks

Pattern: Reusable Query Hooks

// src/api/todos.ts - API functions
export type Todo = {
  id: number
  title: string
  completed: boolean
}

export async function fetchTodos(): Promise<Todo[]> {
  const response = await fetch('/api/todos')
  if 
Compartilhar X LinkedIn