Busca de dados em React e Next.js, comparada em um só app
Busca de dados em React: servidor, TanStack Query, SWR | We.Inc
Escolha uma forma de buscar dados em React com um quiz curto e compare server components, TanStack Query e SWR em cache, mutações e padrões, em um único app de exemplo.
Busque no servidor quando puder: no App Router do Next.js, um server component assíncrono espera os dados antes de enviar qualquer HTML, sem código de spinner de carregamento. Para dados que mudam enquanto a página está aberta, use um cache no cliente como TanStack Query ou SWR, que cuidam de cache, novas tentativas e mutações. Um fetch simples em useEffect serve para requisições pontuais.
Qual abordagem se encaixa
Abordagem
Onde roda
Cache
Melhor para
Server component assíncrono
Servidor
Sem cache por padrão; ative com use cache
Dados da página, segredos, consultas ao banco
TanStack Query
Navegador
Cache de queries indexado por queryKey
Dashboards, mutações, paginação
SWR
Navegador
Cache indexado pela chave da requisição
Telas de muita leitura que devem ficar atualizadas
useEffect + fetch
Navegador
Nenhum, a menos que você escreva
Uma requisição pequena em um app pequeno
Todos os exemplos desta página carregam e editam a mesma pequena lista de notas, então as diferenças vêm da abordagem e não da demonstração. Responda às três perguntas abaixo para receber uma recomendação inicial e o trecho de código correspondente.
Diga se você usa um framework com server components, como o App Router do Next.js.
Diga se os dados precisam se manter atualizados enquanto a página está aberta e se os usuários os editam.
Leia a recomendação e copie o trecho correspondente.
Use as seções de comparação abaixo para conferir os padrões antes de publicar.
Dispare as requisições juntas. Dois awaits seguidos formam uma cascata; crie as duas promises primeiro e faça await em Promise.all.
Use a mesma queryKey em todo useQuery que lê os mesmos dados, para que os componentes compartilhem uma requisição e uma entrada de cache.
Depois de uma mutação, invalide a chave afetada em vez de alterar o cache à mão, a menos que você precise de uma atualização otimista instantânea.
Nunca busque segredos em um client component. Tudo o que o navegador requisita, as pessoas podem ver no painel de rede.
Perguntas frequentes
As requisições fetch ficam em cache no App Router do Next.js?
Segundo a documentação atual do Next.js, as requisições fetch não ficam em cache por padrão e bloqueiam a renderização até terminarem. Requisições idênticas em uma mesma renderização são memoizadas, e você ativa o cache com a diretiva use cache ou faz streaming de dados novos dentro de Suspense.
Quais são os padrões importantes do TanStack Query?
Os dados ficam obsoletos imediatamente (staleTime 0), então são buscados de novo na montagem, no foco da janela e na reconexão. Queries sem uso ficam na memória por 5 minutos (gcTime), e queries que falham tentam de novo 3 vezes com backoff exponencial. Aumente o staleTime se essas novas buscas forem mais do que você precisa.
TanStack Query ou SWR?
Os dois fazem cache por chave e revalidam no foco e na reconexão. O TanStack Query traz mais recursos prontos para mutações, invalidação e devtools; o SWR tem uma API menor, construída em torno de useSWR(key, fetcher). Escolha um por app; usar os dois duplica o cache.
Ainda preciso de uma biblioteca no cliente com server components?
Muitas vezes não, para o carregamento das páginas. Você precisa de uma quando os dados devem se atualizar sem navegação, quando os usuários editam e esperam retorno imediato, ou para listas infinitas. Muitos apps carregam no servidor e usam um cache no cliente só nas telas interativas.
Como devo verificar quem está logado com Supabase no servidor?
O guia de servidor do Supabase diz para nunca confiar em getSession() dentro de código de servidor. Chame supabase.auth.getClaims(), que verifica a assinatura do token, e depois consulte suas tabelas; a row level security continua valendo para toda consulta.
Servidor primeiro, depois um cache no cliente onde for preciso
Um server component pode consultar um banco de dados ou chamar uma API com credenciais diretamente, e o resultado chega como HTML. Isso tira o código de estado de carregamento da maioria das páginas e mantém as chaves fora do bundle do navegador.
Telas interativas são diferentes. Uma lista de notas à qual as pessoas adicionam itens, que filtram e revisitam, ganha com um cache no cliente que lembra os resultados entre telas e os atualiza em segundo plano.
Streaming em vez de esperar
Se uma requisição for lenta, envolva o componente que precisa dela em Suspense com um fallback. O resto da página é enviado na hora e a parte lenta chega por streaming. Um arquivo loading.js faz o mesmo para um segmento de rota inteiro no Next.js.
Em um client component você também pode receber uma promise do servidor e lê-la com a API use do React dentro de Suspense.
Por que o padrão simples com useEffect não basta
Um fetch em useEffect não tem cache, então toda montagem repete a requisição, e ele exige tratar à mão condições de corrida, carregamento e erros. Serve bem para um widget pequeno. Para qualquer coisa maior, uma biblioteca entrega tudo isso em poucas linhas; o básico do próprio fetch está no nosso guia de async e fetch.
Padrões que surpreendem as pessoas
Comportamento de fábrica
Comportamento
fetch no servidor do Next.js
TanStack Query
SWR
Cache entre requisições
Não, ative com use cache
Em memória, por aba do navegador
Em memória, por aba do navegador
Requisições duplicadas
Memoizadas dentro de uma renderização
Compartilhadas por queryKey
Deduplicadas por chave dentro de 2 segundos
Nova busca no foco da janela
Não se aplica
Sim, quando obsoletos
Sim
Nova busca na reconexão
Não se aplica
Sim, quando obsoletos
Sim
Novas tentativas em caso de falha
Você mesmo trata
3, com backoff exponencial
Sim (errorRetryInterval 5000 ms)
Dados sem uso mantidos por
Não se aplica
5 minutos (gcTime)
Não é um padrão documentado
Evitando cascatas no servidor
Dispare as duas requisições e depois espere as duas juntas
Chamar as duas funções antes do await faz com que nenhuma espere pela outra.
Faça streaming de uma parte lenta com Suspense
O título é enviado na hora; a lista de notas chega por streaming quando os dados dela chegam.
Supabase em um server component
Isto usa o helper createClient do guia de servidor do Supabase para Next.js (lib/supabase/server.ts, construído sobre @supabase/ssr). O getClaims() verifica o token do usuário logado antes de a consulta rodar.
Notas do usuário logado, carregadas no servidor
A row level security na tabela notes decide quais linhas voltam.
Escolha uma abordagem
Você usa server components (por exemplo o App Router do Next.js)?
Os dados precisam se atualizar enquanto a página continua aberta?
Os usuários editam estes dados na tela?
Sim
Não
Trecho inicial
Copiar trecho
Carregue em um server component assíncrono. Adicione um cache no cliente depois, só para as partes que ficarem interativas.
Use TanStack Query: useQuery para ler, useMutation para gravar e invalidateQueries para atualizar depois de uma mudança.
Use SWR: o useSWR mantém a tela atualizada no foco e na reconexão com muito pouco código.
Um único fetch em useEffect basta aqui. Faça a limpeza com uma flag ignore para que uma resposta atrasada não sobrescreva um estado mais novo.