Integración Frontend–Backend con TanStack Query
Fetching, caching, mutations y sincronización automática de datos entre tu frontend React y tu API backend.
Hacer fetch de datos en React parece simple hasta que necesitas: caching, re-fetch automático, optimistic updates, manejo de errores y loading states. TanStack Query (antes React Query) resuelve todo esto con una API elegante.
En esta guía vas a integrar tu frontend React con tu API backend usando TanStack Query v5.
Setup
pnpm add @tanstack/react-query
// src/main.tsx
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
const queryClient = new QueryClient({
defaultOptions: {
queries: {
staleTime: 1000 * 60 * 5, // 5 minutos
retry: 1,
},
},
});
ReactDOM.createRoot(document.getElementById("root")!).render(
<QueryClientProvider client={queryClient}>
<App />
</QueryClientProvider>
);
Queries: leer datos
import { useQuery } from "@tanstack/react-query";
function ListaTareas() {
const { data, isLoading, error, refetch } = useQuery({
queryKey: ["tareas"],
queryFn: async () => {
const res = await fetch("/api/tareas");
if (!res.ok) throw new Error("Error al cargar");
return res.json();
},
});
if (isLoading) return <p>Cargando...</p>;
if (error) return <p>Error: {error.message}</p>;
return (
<ul>
{data.datos.map((tarea: any) => (
<li key={tarea.id}>{tarea.titulo}</li>
))}
</ul>
);
}
Query con parámetros
function TareaDetail({ id }: { id: number }) {
const { data } = useQuery({
queryKey: ["tareas", id],
queryFn: () => fetch(`/api/tareas/${id}`).then(r => r.json()),
enabled: !!id, // Solo ejecutar si hay ID
});
if (!data) return null;
return <h1>{data.titulo}</h1>;
}
Mutations: crear, actualizar, eliminar
import { useMutation, useQueryClient } from "@tanstack/react-query";
function CrearTarea() {
const queryClient = useQueryClient();
const mutation = useMutation({
mutationFn: async (titulo: string) => {
const res = await fetch("/api/tareas", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ titulo }),
});
return res.json();
},
onSuccess: () => {
// Invalidar y re-fetch
queryClient.invalidateQueries({ queryKey: ["tareas"] });
},
});
return (
<button onClick={() => mutation.mutate("Nueva tarea")}>
{mutation.isPending ? "Creando..." : "Crear"}
</button>
);
}
Optimistic updates
const mutation = useMutation({
mutationFn: (id: number) => fetch(`/api/tareas/${id}`, { method: "DELETE" }),
onMutate: async (id) => {
// Cancelar queries en curso
await queryClient.cancelQueries({ queryKey: ["tareas"] });
// Guardar estado anterior
const previous = queryClient.getQueryData(["tareas"]);
// Optimistic update
queryClient.setQueryData(["tareas"], (old: any) => ({
...old,
datos: old.datos.filter((t: any) => t.id !== id),
}));
return { previous };
},
onError: (err, id, context) => {
// Rollback en error
queryClient.setQueryData(["tareas"], context?.previous);
},
onSettled: () => {
queryClient.invalidateQueries({ queryKey: ["tareas"] });
},
});
Por qué importa
TanStack Query elimina el 90% del boilerplate de fetching: caching automático, re-fetch en focus, deduplicación de requests, y optimistic updates.
La IA y TanStack Query
Lo bueno
- Generar mutations: la IA crea mutations con invalidation y optimistic updates.
- Configurar queryClient: la IA sugiere staleTime, retry y cacheTime apropiados.
Lo que no debes hacer
- No invalides queries innecesariamente. Cada invalidation triggera un re-fetch.
Desafío: integra tu API
Objetivo: conectar tu frontend React a tu API de Hono con TanStack Query.
Tu tarea:
- Configura QueryClientProvider en tu app
- Crea queries para listar y obtener tareas individuales
- Crea mutations para crear, actualizar y eliminar tareas
- Agrega optimistic update para el toggle de completada
Bonus: implementa infinite scroll con useInfiniteQuery.
Para seguir explorando
Resumen
- TanStack Query maneja fetching, caching, y sincronización de datos en React.
useQuerylee datos con queryKey y queryFn.useMutationcrea/actualiza/elimina datos coninvalidateQueriespara re-fetch.- Optimistic updates mejoran UX mostrando cambios antes de la confirmación del servidor.
staleTimecontrola cuánto tiempo los datos se consideran frescos.
En la próxima guía: Cómo guardar información sensible: hashing vs encriptación — la diferencia que protege a tus usuarios.