Concepto clave
React Query es una biblioteca para manejar datos asíncronos en aplicaciones React y React Native que transforma la forma en que interactúas con APIs, caché y estados de carga. Piensa en ella como un gestor de datos inteligente que automatiza tareas repetitivas como caching, revalidación de datos y sincronización en segundo plano, similar a cómo un asistente personal organiza tus reuniones y te avisa cuando hay cambios.
En lugar de manejar estados de carga, error y datos manualmente con useState y useEffect, React Query proporciona hooks como useQuery y useMutation que encapsulan esta lógica. Esto reduce código boilerplate y mejora la experiencia del usuario con características como refetchOnWindowFocus (recarga automática al volver a la app) y staleTime (control de cuándo los datos se consideran obsoletos). Para desarrolladores avanzados, dominar React Query significa construir apps más rápidas y confiables con menos esfuerzo.
Cómo funciona en la práctica
Para integrar React Query en una app Expo, primero instala las dependencias: npm install @tanstack/react-query. Luego, envuelve tu aplicación en un QueryClientProvider que provee el contexto necesario. Configura un QueryClient con opciones globales como tiempos de caché y reintentos.
Un flujo típico implica: 1) Definir una función fetcher que obtiene datos de una API, 2) Usar useQuery con una clave única y el fetcher, 3) Acceder a estados como isLoading, error y data en tu componente. React Query maneja automáticamente el caching basado en la clave, evitando peticiones redundantes. Para mutaciones (como POST o PUT), useMutation gestiona el envío de datos y actualiza el caché relacionado.
Codigo en accion
Antes: Manejo manual con useState y useEffect en Expo.
import React, { useState, useEffect } from 'react';
import { View, Text, ActivityIndicator } from 'react-native';
const UserList = () => {
const [users, setUsers] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
fetch('https://api.example.com/users')
.then(response => response.json())
.then(data => {
setUsers(data);
setLoading(false);
})
.catch(err => {
setError(err);
setLoading(false);
});
}, []);
if (loading) return ;
if (error) return Error: {error.message};
return (
{users.map(user => (
{user.name}
))}
);
};
export default UserList;Después: Refactorizado con React Query para mejor rendimiento y mantenibilidad.
import React from 'react';
import { View, Text } from 'react-native';
import { useQuery } from '@tanstack/react-query';
const fetchUsers = async () => {
const response = await fetch('https://api.example.com/users');
if (!response.ok) throw new Error('Failed to fetch');
return response.json();
};
const UserList = () => {
const { data: users, isLoading, error } = useQuery({
queryKey: ['users'],
queryFn: fetchUsers,
staleTime: 5 * 60 * 1000, // Datos obsoletos después de 5 minutos
});
if (isLoading) return ;
if (error) return Error: {error.message};
return (
{users.map(user => (
{user.name}
))}
);
};
export default UserList;Errores comunes
- No usar claves de query únicas: Si reutilizas la misma clave para datos diferentes, React Query puede mezclar cachés. Solución: Incluye parámetros dinámicos en la clave, ej: ['users', userId].
- Ignorar staleTime y cacheTime: Configurar staleTime muy bajo causa recargas innecesarias; cacheTime alto consume memoria. Ajusta según la frecuencia de cambio de tus datos.
- Manejar errores solo en UI: No confíes solo en el estado error de useQuery; implementa reintentos automáticos en el QueryClient o usa onError para logging.
- No invalidar queries después de mutaciones: Tras un POST o PUT, olvidar invalidar la query relacionada deja datos desactualizados. Usa queryClient.invalidateQueries({ queryKey: ['users'] }) en onSuccess de useMutation.
- Sobrecargar componentes con lógica de query: Evita poner múltiples useQuery en un componente grande; extrae lógica a hooks personalizados o usa useQueries para paralelismo.
Checklist de dominio
- Configurar QueryClientProvider con opciones globales como defaultOptions en una app Expo.
- Implementar useQuery para fetching de datos con manejo automático de loading, error y caching.
- Usar useMutation para operaciones de escritura (POST, PUT, DELETE) con invalidación de caché.
- Aplicar características avanzadas como prefetching, paginación infinita con useInfiniteQuery.
- Optimizar rendimiento con selectores para transformar datos y evitar re-renders innecesarios.
- Integrar React Query con estado global (ej: Zustand o Context) para datos compartidos.
- Probar queries y mutations con herramientas como React Query Devtools en desarrollo.
Refactorizar una app Expo para usar React Query con API real
En este ejercicio, tomarás una aplicación Expo existente que maneja datos de una API de tareas (todos) con useState y useEffect, y la refactorizarás para usar React Query. Sigue estos pasos:
- Clona o crea un proyecto Expo básico con una pantalla que muestre una lista de tareas desde
https://jsonplaceholder.typicode.com/todosusando el código "antes" proporcionado en la lección. - Instala React Query ejecutando
npm install @tanstack/react-queryen tu terminal. - Envuelve tu componente App en
QueryClientProviderdesde@tanstack/react-query, creando un QueryClient con configuración por defecto (ej: staleTime de 2 minutos). - Reemplaza el useEffect y useState en tu componente de tareas con useQuery. Define una función fetcher que haga la petición a la API y usa la clave de query ['todos'].
- Añade funcionalidad para agregar una nueva tarea: crea un formulario simple y usa useMutation para enviar un POST a la API (puedes simularlo con un mock), luego invalida la query de tareas para actualizar la lista.
- Implementa recarga automática al enfocar la pantalla configurando
refetchOnWindowFocus: trueen tu QueryClient. - Prueba la app en un emulador o dispositivo, verificando que los datos se cachem y las actualizaciones funcionen sin recargas manuales.
- Usa la documentación oficial de TanStack Query para referencia rápida de opciones de configuración.
- Para invalidar queries después de una mutación, accede al queryClient con useQueryClient hook.
- Si la API no soporta POST real, simula la respuesta con un setTimeout y actualiza el caché manualmente con setQueryData.
Evalua tu comprension
Completa el quiz interactivo de arriba para ganar XP.