TechLead

Patrones de Obtención de Datos

Obtención de datos moderna en React — desde useEffect hasta TanStack Query, SWR, Suspense y Componentes de Servidor.

Patrones de Obtención de Datos

La obtención de datos es una de las tareas más comunes en aplicaciones React, y el ecosistema ha evolucionado significativamente. Esta guía cubre desde la obtención manual con useEffect hasta librerías listas para producción como TanStack Query y SWR.

⚠️ La Evolución

useEffect + fetch está bien para aprender, pero las apps de producción deberían usar una librería de datos. Estas manejan caché, revalidación, reintentos y condiciones de carrera — problemas difíciles de resolver correctamente a mano.

1. Patrón Básico: useEffect + fetch

import { useState, useEffect } from "react";

function PerfilUsuario({ userId }) {
  const [usuario, setUsuario] = useState(null);
  const [error, setError] = useState(null);
  const [cargando, setCargando] = useState(true);

  useEffect(() => {
    const controller = new AbortController();

    async function obtenerUsuario() {
      setCargando(true);
      try {
        const res = await fetch(`/api/users/${userId}`, {
          signal: controller.signal,
        });
        if (!res.ok) throw new Error(`HTTP ${res.status}`);
        setUsuario(await res.json());
      } catch (err) {
        if (err.name !== "AbortError") setError(err.message);
      } finally {
        setCargando(false);
      }
    }

    obtenerUsuario();
    return () => controller.abort();
  }, [userId]);

  if (cargando) return <p>Cargando...</p>;
  if (error) return <p>Error: {error}</p>;
  return <div>{usuario.nombre}</div>;
}

2. TanStack Query (React Query)

La librería más popular para obtención de datos en React. Maneja caché, revalidación en segundo plano, paginación y actualizaciones optimistas.

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

function Posts() {
  const { data: posts, isLoading, error } = useQuery({
    queryKey: ["posts"],
    queryFn: () => fetch("/api/posts").then((r) => r.json()),
    staleTime: 5 * 60 * 1000,  // 5 min antes de ser "obsoleto"
    retry: 3,                   // Reintentar solicitudes fallidas
  });

  if (isLoading) return <p>Cargando...</p>;
  if (error) return <p>Error: {error.message}</p>;

  return posts.map((post) => <h3 key={post.id}>{post.titulo}</h3>);
}

Mutaciones con TanStack Query

function CrearPost() {
  const queryClient = useQueryClient();

  const mutation = useMutation({
    mutationFn: (nuevoPost) =>
      fetch("/api/posts", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify(nuevoPost),
      }).then((r) => r.json()),

    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ["posts"] });
    },
  });

  return (
    <button onClick={() => mutation.mutate({ titulo: "Nuevo" })}>
      {mutation.isPending ? "Creando..." : "Crear Post"}
    </button>
  );
}

3. SWR (Stale-While-Revalidate)

import useSWR from "swr";

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

function PerfilUsuario({ userId }) {
  const { data, error, isLoading } = useSWR(
    `/api/users/${userId}`,
    fetcher,
    {
      revalidateOnFocus: true,
      revalidateOnReconnect: true,
    }
  );

  if (isLoading) return <p>Cargando...</p>;
  if (error) return <p>Error al cargar usuario</p>;
  return <h2>{data.nombre}</h2>;
}

4. Suspense para Datos

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

function DetallesUsuario({ userId }) {
  const { data: usuario } = useSuspenseQuery({
    queryKey: ["user", userId],
    queryFn: () => fetch(`/api/users/${userId}`).then((r) => r.json()),
  });

  return <h2>{usuario.nombre}</h2>;
}

function PaginaUsuario({ userId }) {
  return (
    <Suspense fallback={<p>Cargando...</p>}>
      <DetallesUsuario userId={userId} />
    </Suspense>
  );
}

✅ ¿Qué Librería Usar?

Escenario Recomendación
Aprendizaje / app simple Hook personalizado useFetch
SPA del lado del cliente TanStack Query
Next.js / Stack Vercel SWR
Next.js App Router Server Components + TanStack Query para partes del cliente