DevPath · Aprenda a programar ESPTEN

Dados e estado global

Data fetching moderno: TanStack Query e SWR

O problema do useEffect + fetch na mão

Carregar dados do servidor parece simples: um useEffect que faz fetch e guarda o resultado no estado. É a primeira coisa que aprendemos, e para um caso isolado funciona:

function Perfil({ userId }) {
  const [usuario, setUsuario] = useState(null);
  const [carregando, setCarregando] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    let cancelado = false;
    setCarregando(true);
    fetch(`/api/usuarios/${userId}`)
      .then((r) => {
        if (!r.ok) throw new Error("Error " + r.status);
        return r.json();
      })
      .then((data) => { if (!cancelado) setUsuario(data); })
      .catch((e) => { if (!cancelado) setError(e); })
      .finally(() => { if (!cancelado) setCarregando(false); });
    return () => { cancelado = true; };
  }, [userId]);

  // ...renderização conforme carregando / error / usuario
}

Veja quanto código de encanamento existe para uma única requisição, e ainda faltam coisas. Quando o app cresce, este padrão fica aquém porque cada tela precisa reinventar:

Esses problemas não são do estado do cliente (o que o usuário digita ou seleciona): são do estado do servidor, dados que vivem remotamente, que cacheamos no cliente e que podem ficar desatualizados. As bibliotecas de data fetching nascem para gerenciar exatamente isso.

TanStack Query (React Query)

TanStack Query trata o estado do servidor como um recurso com cache. A peça central é o hook useQuery:

import { useQuery } from "@tanstack/react-query";

function Perfil({ userId }) {
  const { data, isLoading, error } = useQuery({
    queryKey: ["usuario", userId],
    queryFn: () =>
      fetch(`/api/usuarios/${userId}`).then((r) => r.json()),
    staleTime: 60_000, // dados "frescos" durante 60 s
  });

  if (isLoading) return <p>Carregando…</p>;
  if (error) return <p>Algo deu errado</p>;
  return <h1>{data.nome}</h1>;
}

As chaves:

Tudo o que antes você escrevia na mão —cache, deduplicação, revalidação, cancelamento— vem de fábrica.

SWR

SWR (da Vercel) segue a mesma filosofia com uma API mais minimalista. Seu nome vem de stale-while-revalidate: mostra os dados cacheados (stale) na hora e, em paralelo, revalida em segundo plano.

import useSWR from "swr";

const fetcher = (url) => fetch(url).then((r) => r.json());

function Perfil({ userId }) {
  const { data, error, isLoading } = useSWR(
    `/api/usuarios/${userId}`,
    fetcher
  );

  if (isLoading) return <p>Carregando…</p>;
  if (error) return <p>Algo deu errado</p>;
  return <h1>{data.nome}</h1>;
}

Aqui a chave de cache é a própria URL (primeiro argumento) e o fetcher é a função de download. O SWR também deduplica requisições, revalida ao refocar e reconectar, e expõe mutate() para atualizar o cache.

Ideia-chave: separe o estado do servidor (dados remotos cacheados → TanStack Query / SWR) do estado do cliente (UI local → useState, Zustand...). Não coloque dados do servidor em um store global "na mão"; deixe que uma biblioteca de queries gerencie seu cache e seu frescor.

(Essas bibliotecas são instaladas à parte; aqui as estudamos de forma conceitual. Nos exercícios validáveis seguimos usando os hooks nativos do React.)

Coloque isto em prática

O DevPath é um curso prático: aqui você lê a teoria; no app você a coloca em prática com exercícios que rodam de verdade, offline.

Comece grátis no app →
Estado global: além do Context →