Desarrollo

Mejora el rendimiento de Next.js con TanStack Query (React Query)

Cómo TanStack Query mejora el rendimiento de Next.js: caché, revalidación en segundo plano, mutaciones y SSR/SSG hidratado.

By Mohamed DjoudirOctober 05, 20254 min read
Compartir:
Mejora el rendimiento de Next.js con TanStack Query (React Query)
#Next.js#React Query#TanStack Query#Rendimiento#Caché

Gestionar correctamente el estado del servidor es una de las palancas de rendimiento más infravaloradas en Next.js. Con patrones manuales (fetch + useEffect) aparece código repetido, condiciones de carrera y múltiples solicitudes idénticas.

TanStack Query convierte ese caos en una capa declarativa: define clave, función y política de caducidad; el framework hace el resto.


¿Por qué el fetching suele ser un cuello de botella oculto?

Patrones problemáticos comunes:

  • Repetir la misma petición en componentes distintos.
  • Hacer transiciones de página completas para cambios puntuales.
  • Usar estado global para datos del servidor (abstracción incorrecta).
  • No aprovechar un caché compartido entre navegaciones.
  • Refetch agresivo al volver el foco → presión sobre la API.

Resultado: más latencia percibida y navegación menos fluida.

TanStack Query estandariza frescura, caducidad e invalidación → menos sorpresas.


Lo que obtienes con TanStack Query

  • De-duplicación y caché compartido.
  • Stale-While-Revalidate: pintado inmediato + actualización silenciosa.
  • Recolección automática de queries no usados.
  • Invalidation específico tras mutaciones.
  • Hidratación SSR/SSG para mejor primer render y SEO.

Instalación

yarn add @tanstack/react-query

Compatible con App Router (Next.js 13/14). No dependemos de APIs nuevas de 15+.


Proveedor global del QueryClient

1"use client";
2import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
3import { useState, ReactNode } from "react";
4
5export function QueryProviders({ children }: { children: ReactNode }) {
6  const [queryClient] = useState(() => new QueryClient());
7  return <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>;
8}

En app/layout.tsx:

1import { QueryProviders } from "@/app/query-providers";
2
3export default function RootLayout({ children }: { children: React.ReactNode }) {
4  return (
5    <html lang="es">
6      <body>
7        <QueryProviders>{children}</QueryProviders>
8      </body>
9    </html>
10  );
11}

Fetch imperativo vs declarativo

Sin TanStack Query:

1const [posts, setPosts] = useState([]);
2const [loading, setLoading] = useState(true);
3useEffect(() => {
4  let cancelado = false;
5  fetch("/api/posts")
6    .then(r => r.json())
7    .then(d => { if (!cancelado) { setPosts(d); setLoading(false); } });
8  return () => { cancelado = true; };
9}, []);

Con TanStack Query:

1"use client";
2import { useQuery } from "@tanstack/react-query";
3
4async function fetchPosts() {
5  const res = await fetch("https://jsonplaceholder.typicode.com/posts");
6  if (!res.ok) throw new Error("Error al obtener posts");
7  return res.json();
8}
9
10export function PostsList() {
11  const { data, isLoading, isError } = useQuery({
12    queryKey: ["posts"],
13    queryFn: fetchPosts,
14    staleTime: 60_000,
15  });
16  if (isLoading) return <p>Cargando…</p>;
17  if (isError) return <p>No se pudieron cargar los datos.</p>;
18  return <ul>{data.map((p: any) => <li key={p.id}>{p.title}</li>)}</ul>;
19}

Beneficios: menos código, reutilización instantánea de caché, menos solicitudes.


Mutaciones e invalidación

1import { useMutation, useQueryClient } from "@tanstack/react-query";
2
3export function AddTodoButton() {
4  const qc = useQueryClient();
5  const mutation = useMutation({
6    mutationFn: async (nuevo: { title: string }) => {
7      await fetch("/api/todos", {
8        method: "POST",
9        headers: { "Content-Type": "application/json" },
10        body: JSON.stringify(nuevo),
11      });
12    },
13    onSuccess: () => qc.invalidateQueries({ queryKey: ["todos"] }),
14  });
15  return (
16    <button onClick={() => mutation.mutate({ title: "Aprender TanStack Query" })}>
17      {mutation.isPending ? "Guardando…" : "Añadir"}
18    </button>
19  );
20}

Secuencia clara → acción usuario → mutación → invalidación dirigida → UI fresca.


Hidratación SSR / SSG (pre 15)

1// pages/posts.tsx
2import { QueryClient, dehydrate } from "@tanstack/react-query";
3import { useQuery } from "@tanstack/react-query";
4
5async function fetchPosts() {
6  const r = await fetch("https://jsonplaceholder.typicode.com/posts");
7  return r.json();
8}
9
10export async function getStaticProps() {
11  const qc = new QueryClient();
12  await qc.prefetchQuery({ queryKey: ["posts"], queryFn: fetchPosts });
13  return { props: { dehydratedState: dehydrate(qc) }, revalidate: 3600 };
14}
15
16export default function PostsPage() {
17  const { data } = useQuery({ queryKey: ["posts"], queryFn: fetchPosts });
18  return (
19    <main>
20      <h1>Todos los posts</h1>
21      <ul>{data?.map((p: any) => <li key={p.id}>{p.title}</li>)}</ul>
22    </main>
23  );
24}

Consejos de rendimiento

  1. Ajusta staleTime por dominio de datos.
  2. Desactiva refetchOnWindowFocus si no aporta valor.
  3. Prefetch en hover de enlaces clave.
  4. Invalidación granular > invalidación global.
  5. Centraliza claves en un helper.
  6. Usa actualizaciones optimistas para UX de baja latencia.

Por qué lo usamos en Aniq‑UI

  • Menos boilerplate para quien compra la plantilla.
  • Mejor sensación de velocidad entre rutas.
  • Separa claramente estado de servidor y UI.
  • Ayuda a Core Web Vitals.

Conclusión

TanStack Query convierte efectos dispersos en una capa de caché consistente y escalable. Es una apuesta segura para proyectos que deben mantenerse en el tiempo y plantillas reutilizables.

Mira ejemplos reales en plantillas Next.js listas para producción en Aniq‑UI.com.

Palabras clave SEO: rendimiento Next.js, React Query Next.js, TanStack Query, plantillas Next.js, caché Next.js, fetching datos Next.js

¿Encontró útil este artículo?

Compartir:
world map

Comunidad Global de Usuarios

Únete a miles de desarrolladores en todo el mundo que confían en Aniq-UI para sus proyectos. Nuestras plantillas se utilizan en todo el mundo para crear experiencias web impresionantes.

Contáctanos

Need custom work or reskin? Get in touch with us

Aniq-uiAniq-uiAniq-ui