Skip to content

Características y Ventajas

Características y Ventajas de TanStack Query

Section titled “Características y Ventajas de TanStack Query”

TanStack Query no es solo otra librería de fetching de datos. Es una solución completa que aporta características avanzadas que mejoran significativamente la experiencia de desarrollo y del usuario final.

El cache de TanStack Query es su característica más poderosa:

// Primera vez - fetch desde el servidor
const { data } = useQuery({
queryKey: ['user', 1],
queryFn: () => fetchUser(1)
});
// Otras veces - desde cache instantáneo
const { data } = useQuery({
queryKey: ['user', 1], // Misma key = mismos datos
queryFn: () => fetchUser(1)
});

Beneficios del Cache:

  • Respuesta instantánea para datos ya cargados
  • 🔄 Sincronización automática entre componentes
  • 💾 Persistencia opcional entre sesiones
  • 🎯 Invalidación inteligente cuando es necesario

Los datos se actualizan automáticamente en segundo plano:

const { data } = useQuery({
queryKey: ['posts'],
queryFn: fetchPosts,
staleTime: 5 * 60 * 1000, // 5 minutos
refetchOnWindowFocus: true, // Refetch al enfocar ventana
refetchInterval: 30000 // Refetch cada 30 segundos
});

Cuándo se actualiza automáticamente:

  • 🔍 Cuando la ventana recupera el foco
  • 🌐 Cuando se reconecta la red
  • ⏰ En intervalos configurables
  • 🔄 Cuando se considera que los datos están “stale”

Múltiples componentes pueden usar la misma query sin duplicar peticiones:

// Componente A
function UserProfile() {
const { data } = useQuery({
queryKey: ['user', userId],
queryFn: () => fetchUser(userId)
});
}
// Componente B (se ejecuta simultáneamente)
function UserSettings() {
const { data } = useQuery({
queryKey: ['user', userId], // Misma key!
queryFn: () => fetchUser(userId) // Solo se ejecuta UNA vez
});
}

Control preciso sobre todos los estados de la petición:

const {
data,
isLoading, // Primera carga
isFetching, // Cualquier petición en chapter
isStale, // Si los datos están obsoletos
isError, // Si hay error
error, // El error específico
failureCount, // Número de reintentos fallidos
refetch // Función para recargar
} = useQuery({
queryKey: ['data'],
queryFn: fetchData
});
// UI granular basada en estados
if (isLoading) return <Skeleton />;
if (isError) return <ErrorBoundary error={error} />;
if (isFetching && !isLoading) return <LoadingIndicator />;

Reintentos inteligentes con backoff exponencial:

const { data } = useQuery({
queryKey: ['flaky-api'],
queryFn: fetchFlakyData,
retry: 3, // Reintentar 3 veces
retryDelay: attemptIndex => Math.min(1000 * 2 ** attemptIndex, 30000)
});

Actualiza la UI inmediatamente, antes de confirmar con el servidor:

const updateUser = useMutation({
mutationFn: updateUserAPI,
onMutate: async (newUser) => {
// Actualización optimista
queryClient.setQueryData(['user', userId], newUser);
},
onError: (err, newUser, context) => {
// Rollback si falla
queryClient.setQueryData(['user', userId], context.previousUser);
}
});
// Sin TanStack Query: Loading en cada navegación
function ProductList() {
const [products, setProducts] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
// Siempre loading al montar
setLoading(true);
fetchProducts().then(data => {
setProducts(data);
setLoading(false);
});
}, []);
}
// Con TanStack Query: Datos instantáneos desde cache
function ProductList() {
const { data: products, isLoading } = useQuery({
queryKey: ['products'],
queryFn: fetchProducts
});
// isLoading solo es true la primera vez
}
FuncionalidadSin TanStack QueryCon TanStack Query
Fetching básico~20 líneas~5 líneas
Cache manual~50 líneas0 líneas (automático)
Retry logic~30 líneas1 línea de config
Loading states~15 líneasIncluido automáticamente
Error handling~20 líneasIncluido automáticamente
// Antes: N peticiones duplicadas
function App() {
return (
<div>
<Header /> {/* fetchUser() */}
<Sidebar /> {/* fetchUser() */}
<Profile /> {/* fetchUser() */}
</div>
);
}
// Después: 1 petición, 3 componentes actualizados
function App() {
return (
<div>
<Header /> {/* useQuery(['user']) */}
<Sidebar /> {/* useQuery(['user']) - desde cache */}
<Profile /> {/* useQuery(['user']) - desde cache */}
</div>
);
}
// Instalar React Query DevTools
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
function App() {
return (
<>
<MyApp />
<ReactQueryDevtools initialIsOpen={false} />
</>
);
}
// Inferencia automática de tipos
const { data } = useQuery({
queryKey: ['user', userId],
queryFn: (): Promise<User> => fetchUser(userId)
// data es automáticamente de tipo User | undefined
});

TanStack Query escala naturalmente:

// Simple: Una query
const { data: user } = useQuery({
queryKey: ['user'],
queryFn: fetchUser
});
// Complejo: Queries dependientes
const { data: user } = useQuery({
queryKey: ['user'],
queryFn: fetchUser
});
const { data: posts } = useQuery({
queryKey: ['posts', user?.id],
queryFn: () => fetchUserPosts(user.id),
enabled: !!user?.id // Solo ejecutar si user existe
});
AspectouseState + useEffectTanStack Query
Código requerido15-30 líneas3-5 líneas
CacheManualAutomático
DeduplicaciónNo
Background updatesManualAutomático
Error handlingManualAutomático
Loading statesManualAutomático
AspectoRTK QueryTanStack Query
Curva de aprendizajeAltaMedia
Bundle size~50kb~13kb
Cache invalidationManual/TagsAutomático/Manual
DevToolsRedux DevToolsQuery DevTools
Framework agnosticNo (Redux)
AspectoSWRTanStack Query
APIMás simpleMás completa
MutationsBásicasAvanzadas
DevToolsNoExcelentes
Infinite queriesLimitadoCompleto
Parallel queriesManualAutomático

TanStack Query es perfecto para:

Aplicaciones data-intensive (dashboards, admin panels)
Apps con mucha navegación (SPAs complejas)
Datos que cambian frecuentemente (feeds, notificaciones)
Aplicaciones colaborativas (múltiples usuarios)
Apps mobile-first (conexiones intermitentes)

No usar para:

  • Aplicaciones muy simples con pocas peticiones
  • Estado puramente local (formularios, UI state)
  • Aplicaciones estáticas sin APIs

Próximo paso: Estado local y del servidor