Cache | TanStack | React
- Cache | TanStack | React
Cache no TanStack Query no Next.js (App Router)
O TanStack Query implementa cache em memória no lado do cliente.
Ele evita requisições repetidas enquanto os dados estiverem considerados válidos (fresh) e enquanto o QueryClient estiver ativo.
Essa documentação descreve:
- Como o cache é ativado
- Como ele funciona internamente
- Quando ele não funciona
- Configuração correta em Next.js
- Cenários reais de comportamento
Arquitetura do Cache
O cache depende de três elementos:
QueryClientQueryClientProvideruseQuery
Fluxo simplificado:
useQuery → verifica cache pelo queryKey
→ se não existir → executa queryFn
→ salva resultado no QueryClient
→ retorna dados para o componente
Se o queryKey já existir e estiver dentro do staleTime, nenhuma nova requisição é feita.
Configuração Base
QueryClient
import { QueryClient } from '@tanstack/react-query'
export const queryClient = new QueryClient({
defaultOptions: {
queries: {
staleTime: 5 * 60 * 1000,
gcTime: 10 * 60 * 1000,
refetchOnWindowFocus: false,
},
},
})
Provider (deve estar no layout raiz)
"use client"
import { QueryClientProvider } from "@tanstack/react-query"
import { queryClient } from "@/lib/queryClient"
export function ReactQueryProvider({ children }) {
return (
<QueryClientProvider client={queryClient}>
{children}
</QueryClientProvider>
)
}
Se o provider desmontar, o cache é destruído.
Parâmetros que Controlam o Cache
staleTime
Define por quanto tempo os dados são considerados frescos.
staleTime: 5 * 60 * 1000
Enquanto estiver fresco:
- Não ocorre refetch automático
- Mesmo ao navegar entre rotas
Se for:
staleTime: Infinity
Nunca refaz automaticamente.
gcTime (antigo cacheTime)
Tempo que o cache permanece em memória após não estar sendo usado.
gcTime: 10 * 60 * 1000
Se nenhum componente estiver usando a query e o tempo expirar, o cache é removido.
refetchOnWindowFocus
Controla se refaz a requisição ao voltar para a aba.
refetchOnWindowFocus: false
refetchOnMount
Controla se refaz ao montar o componente.
refetchOnMount: false
refetchOnReconnect
Refaz ao reconectar à internet.
refetchOnReconnect: true
Quando o Cache Funciona
O cache funciona quando:
- Navegação ocorre via
<Link />ourouter.push - O
QueryClientProviderpermanece montado - A página não foi recarregada
- O tempo de
staleTimeainda não expirou
Exemplo:
- Acessa
/products - Dados carregam
- Vai para
/ - Volta para
/productsdentro de 5 minutos
Resultado:
→ Nenhuma nova requisição é feita
Quando o Cache Não Funciona
1. Hard Reload (F5)
Ao recarregar a página:
- React reinicia
- QueryClient é recriado
- Cache em memória é perdido
2. Digitar URL manualmente + Enter
Isso provoca reload completo do navegador.
Mesmo comportamento do F5.
3. Provider fora do layout raiz
Se o QueryClientProvider estiver:
- Dentro da página
- Em um layout intermediário
Ao navegar, ele desmonta e o cache é perdido.
Estrutura correta:
app/layout.tsx
└── ReactQueryProvider
└── children
4. QueryClient sendo recriado
Errado:
function Provider() {
const queryClient = new QueryClient()
}
Correto:
const queryClient = new QueryClient()
5. Strict Mode em desenvolvimento
No Next.js:
reactStrictMode: true
Em ambiente DEV:
- O componente monta duas vezes
- A query pode executar duas vezes
Isso não acontece em produção.
Teste real:
npm run build
npm start
Comportamento Visual Simplificado
Primeira vez na página
Cache vazio → Executa query → Armazena resultado
Voltar dentro do staleTime
Cache válido → Retorna do cache → Sem request
Após staleTime expirar
Cache stale → Executa nova request
Estratégia de Cache Estável
Configuração para evitar qualquer refetch automático:
useQuery({
queryKey: ['products'],
queryFn: getProductsAsync,
staleTime: Infinity,
gcTime: Infinity,
refetchOnMount: false,
refetchOnWindowFocus: false,
refetchOnReconnect: false,
})
Nesse cenário, só haverá nova requisição se:
queryClient.invalidateQueries({ queryKey: ['products'] })
Persistência de Cache após Reload
Por padrão, o cache é apenas em memória.
Para manter após F5:
npm install @tanstack/react-query-persist-client
Exemplo com localStorage:
import { persistQueryClient } from '@tanstack/react-query-persist-client'
import { createSyncStoragePersister } from '@tanstack/query-sync-storage-persister'
const persister = createSyncStoragePersister({
storage: window.localStorage,
})
persistQueryClient({
queryClient,
persister,
})
Agora o cache sobrevive a reload.
Diagnóstico Prático
Se estiver vendo requisição na aba Network:
- Verifique se é a primeira execução
- Teste navegação via Link
- Teste sem dar F5
- Confirme se o Provider está no layout raiz
- Teste build de produção
Resumo Técnico
O cache do TanStack Query:
- É client-side
- É em memória
- Depende do lifecycle do React
- Não sobrevive a reload por padrão
- Funciona corretamente com navegação SPA