TanStack Query: Gerenciamento de Cache e Dados Assíncronos em React

O Problema do Estado Server-Side no React
Gerenciar dados vindos de APIs sempre foi um dos maiores desafios no desenvolvimento React. Tradicionalmente, os desenvolvedores precisam lidar manualmente com estados de loading, success e error, além de caching, revalidação, paginação e refetch — tudo isso resultando em dezenas de linhas de useEffect, useReducer e useState por tela.
O TanStack Query (anteriormente conhecido como React Query) surge como uma biblioteca que trata o estado server-side como um cidadão de primeira classe, abstraindo toda a complexidade de sincronização entre sua aplicação e servidores.
O que é o TanStack Query?
O TanStack Query é uma biblioteca de gerenciamento de estado assíncrono que permite:
- Autogestão de Cache: Armazena dados em memória com políticas inteligentes de stale/refetch
- Dedução de Requisições: Múltiplos componentes usando o mesmo dado não disparam requisições duplicadas
- Revalidação Automática: Refetch inteligente baseado em tempo, foco da janela, reconexão de rede
- Pagineção e Infinite Scroll: Hooks dedicados para listas paginadas com prefetch
- Mutações Otimistas: Atualiza a UI antes da resposta do servidor para experiência fluida
Instalação e Primeiro Hook
A instalação é simples com seu gerenciador de pacotes favorito:
npm install @tanstack/react-query
# ou
pnpm add @tanstack/react-queryO coração da biblioteca é o hook useQuery, que recebe uma chave única para cache e uma função assíncrona de fetch:
import { useQuery } from '@tanstack/react-query';
import { getUser } from './api';
function UserProfile({ userId }) {
const { data, isLoading, error } = useQuery({
queryKey: ['user', userId],
queryFn: () => getUser(userId),
});
if (isLoading) return <Skeleton />;
if (error) return <ErrorBanner />;
return <h1>{data.name}</h1>;
}Estratégias de Cache e Stale Time
O TanStack Query oferece um modelo de cache extremamente flexível. Três configurações são fundamentais:
staleTime: Tempo em milissegundos antes dos dados serem considerados obsoletos. Dados ainda frescos nunca são refetched automaticamente.gcTime: (antigocacheTime) — tempo que os dados inativos permanecem no cache antes de serem removidos da memória.refetchInterval: Polling automático para dados que precisam de atualização constante, como dashboards em tempo real.
const { data } = useQuery({
queryKey: ['dashboard', dateRange],
queryFn: () => fetchDashboard(dateRange),
staleTime: 5 * 60 * 1000, // 5 minutos
gcTime: 30 * 60 * 1000, // 30 minutos
refetchInterval: 60 * 1000, // refetch a cada 1 minuto
});Mutações com Atualização Otimista
Mutações no TanStack Query são feitas com useMutation. O recurso mais poderoso é a atualização otimista, onde a UI já reflete a mudança antes da confirmação do servidor:
const mutation = useMutation({
mutationFn: updateTodo,
onMutate: async (newTodo) => {
await queryClient.cancelQueries({ queryKey: ['todos'] });
const previous = queryClient.getQueriesData(['todos']);
queryClient.setQueryData(['todos'], (old) =>
old.map(t => t.id === newTodo.id ? { ...t, ...newTodo } : t)
);
return { previous };
},
onError: (err, newTodo, context) => {
queryClient.setQueryData(['todos'], context.previous);
},
});Pagineção e Infinite Scroll
Para listas paginadas, o hook useInfiniteQuery gerencia múltiplas páginas automaticamente:
const {
data,
fetchNextPage,
hasNextPage,
isFetchingNextPage,
} = useInfiniteQuery({
queryKey: ['projects'],
queryFn: ({ pageParam = 1 }) => fetchProjects(pageParam),
getNextPageParam: (lastPage) => lastPage.nextPage ?? undefined,
});
// No componente:
{data.pages.map(page =>
page.projects.map(project => <Card key={project.id} />)
)}
<Button
onClick={() => fetchNextPage()}
disabled={!hasNextPage}
>
{isFetchingNextPage ? 'Carregando...' : 'Carregar mais'}
</Button>Devtools: Inspecione seu Cache em Tempo Real
O TanStack Query vem com Devtools dedicados que permitem inspecionar todo o cache, visualizar queries ativas, forçar refetch, e depurar seus dados:
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
function App() {
return (
<QueryClientProvider client={queryClient}>
<RouterProvider router={router} />
<ReactQueryDevtools initialIsOpen={false} />
</QueryClientProvider>
);
}TanStack Query vs. Estado Global (Redux, Zustand)
Uma confusão comum é tratar o TanStack Query como um substituto do Redux ou Zustand. Na prática, eles resolvem problemas diferentes:
TanStack Query é ideal para dados do servidor — cache automático, refetch inteligente, mutações com rollback. Redux / Zustand é melhor para estado da UI — tema, modais, formulários.
A abordagem moderna é usar TanStack Query + Zustand — um para dados remotos e outro para estado local — eliminando a necessidade de soluções monolíticas que misturam os dois mundos.
Conclusão
O TanStack Query se consolidou como a biblioteca padrão para sincronização de dados em aplicações React modernas. Com mais de 40 mil estrelas no GitHub e adoção massiva em projetos de todos os portes, ele resolve de forma elegante o problema mais comum e complexo do front-end moderno: manter a UI sincronizada com o servidor sem perder performance, legibilidade ou controle.
Se você ainda usa useEffect + fetch para cada chamada de API, está na hora de experimentar o TanStack Query — seus estados de loading, cache e mutações vão agradecer.







