React Query (TanStack Query)
Esta skill orienta a implementação de gerenciamento de dados assíncronos usando @tanstack/react-query v5, seguindo os padrões estabelecidos neste projeto.
Quando usar esta skill
- Buscar dados do servidor - Listagens, detalhes, dados paginados
- Criar, atualizar ou deletar recursos - Operações CRUD com feedback visual
- Sincronizar cache automaticamente - Invalidar queries após mutations
- Gerenciar loading/error states - Estados de carregamento e erro de forma declarativa
Como usar
1. Estrutura de Arquivos
Os hooks de React Query devem seguir a estrutura feature-based:
src/features/{feature-name}/
├── actions/ # Server actions (Next.js)
├──action.ts
├── schemas/ # Tipos e validações Zod
├──schema.ts
├── hooks/
├── use-{entities}.ts # Query para listar (ex: use-services.ts)
├── use-create-{entity}.ts # Mutation para criar
├── use-update-{entity}.ts # Mutation para atualizar
└── use-delete-{entity}.ts # Mutation para deletar
2. Convenções de Nomenclatura
| Tipo | Padrão | Exemplo |
|---|---|---|
| Query (listar) | use{Entities} | useServices, useUsers |
| Query (detalhe) | use{Entity} | useService, useUser |
| Mutation (criar) | useCreate{Entity} | useCreateService |
| Mutation (atualizar) | useUpdate{Entity} | useUpdateService |
| Mutation (deletar) | useDelete{Entity} | useDeleteService |
3. Query Keys
Use arrays estruturados para query keys:
typescript1// ✅ Bom - permite invalidação granular 2queryKey: ["services"]; // Lista todos 3queryKey: ["services", { onlyActive: true }]; // Lista com filtro 4queryKey: ["services", id]; // Detalhe por ID 5 6// ❌ Evitar - dificulta invalidação 7queryKey: ["all-services"]; 8queryKey: [`service-${id}`];
4. Padrão de useQuery (Buscar Dados)
typescript1"use client"; 2 3import { useQuery } from "@tanstack/react-query"; 4import { getEntities } from "../actions"; 5 6export function useEntities(filter?: boolean) { 7 return useQuery({ 8 queryKey: ["entities", { filter }], 9 queryFn: () => getEntities(filter), 10 }); 11}
5. Padrão de useMutation (Modificar Dados)
typescript1"use client"; 2 3import { useMutation, useQueryClient } from "@tanstack/react-query"; 4import { toast } from "sonner"; 5import { createEntity } from "../actions"; 6import type { CreateEntityInput } from "../schemas"; 7 8export function useCreateEntity() { 9 const queryClient = useQueryClient(); 10 11 return useMutation({ 12 mutationFn: (data: CreateEntityInput) => createEntity(data), 13 onSuccess: (result) => { 14 if (result.success) { 15 toast.success("Criado com sucesso!"); 16 queryClient.invalidateQueries({ queryKey: ["entities"] }); 17 } else { 18 toast.error("Erro ao criar"); 19 } 20 }, 21 onError: () => { 22 toast.error("Erro ao criar"); 23 }, 24 }); 25}
6. Uso em Componentes
tsx1"use client"; 2 3import { useEntities } from "../hooks/use-entities"; 4import { useCreateEntity } from "../hooks/use-create-entity"; 5 6export function EntitiesTable() { 7 const { data, isLoading, error } = useEntities(); 8 const createMutation = useCreateEntity(); 9 10 if (isLoading) return <Loading />; 11 if (error) return <Error message={error.message} />; 12 13 const handleCreate = (data: CreateEntityInput) => { 14 createMutation.mutate(data); 15 }; 16 17 return <Table data={data} />; 18}
Regras importantes
[!IMPORTANT] Todos os hooks de React Query devem incluir
"use client"no topo do arquivo.
[!TIP] Sempre invalide queries relacionadas após uma mutation para manter o cache sincronizado.
[!WARNING] Não use
queryClient.setQueryDatapara modificar o cache diretamente, prefirainvalidateQueriespara garantir dados frescos.