Integracion con APIs
Obtener datos de APIs con fetch y React Query
Obteniendo Datos en React
Las aplicaciones React frecuentemente necesitan obtener datos de APIs. Hay varias formas de hacerlo, desde fetch nativo hasta librerias especializadas.
Fetch Basico con useEffect
import { useState, useEffect } from 'react';
function ListaUsuarios() {
const [usuarios, setUsuarios] = useState([]);
const [cargando, setCargando] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const obtenerUsuarios = async () => {
try {
const respuesta = await fetch('https://api.ejemplo.com/usuarios');
if (!respuesta.ok) {
throw new Error('Error al obtener usuarios');
}
const datos = await respuesta.json();
setUsuarios(datos);
} catch (err) {
setError(err.message);
} finally {
setCargando(false);
}
};
obtenerUsuarios();
}, []);
if (cargando) return <p>Cargando...</p>;
if (error) return <p>Error: {error}</p>;
return (
<ul>
{usuarios.map(usuario => (
<li key={usuario.id}>{usuario.nombre}</li>
))}
</ul>
);
}
Hook Personalizado para Fetch
function useFetch(url) {
const [datos, setDatos] = useState(null);
const [cargando, setCargando] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const abortController = new AbortController();
const obtenerDatos = async () => {
try {
const respuesta = await fetch(url, {
signal: abortController.signal
});
if (!respuesta.ok) throw new Error('Error de red');
const datos = await respuesta.json();
setDatos(datos);
} catch (err) {
if (err.name !== 'AbortError') {
setError(err.message);
}
} finally {
setCargando(false);
}
};
obtenerDatos();
return () => abortController.abort();
}, [url]);
return { datos, cargando, error };
}
// Uso
function Usuarios() {
const { datos: usuarios, cargando, error } = useFetch('/api/usuarios');
if (cargando) return <p>Cargando...</p>;
if (error) return <p>Error: {error}</p>;
return <ul>{usuarios.map(u => <li key={u.id}>{u.nombre}</li>)}</ul>;
}
Enviando Datos (POST/PUT/DELETE)
function FormularioUsuario() {
const [nombre, setNombre] = useState('');
const [enviando, setEnviando] = useState(false);
const crearUsuario = async (e) => {
e.preventDefault();
setEnviando(true);
try {
const respuesta = await fetch('/api/usuarios', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ nombre }),
});
if (!respuesta.ok) throw new Error('Error al crear usuario');
const nuevoUsuario = await respuesta.json();
console.log('Usuario creado:', nuevoUsuario);
setNombre('');
} catch (error) {
console.error('Error:', error);
} finally {
setEnviando(false);
}
};
return (
<form onSubmit={crearUsuario}>
<input
value={nombre}
onChange={(e) => setNombre(e.target.value)}
disabled={enviando}
/>
<button type="submit" disabled={enviando}>
{enviando ? 'Creando...' : 'Crear Usuario'}
</button>
</form>
);
}
TanStack Query (React Query)
// npm install @tanstack/react-query
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
// Obtener datos
function Usuarios() {
const { data: usuarios, isLoading, error } = useQuery({
queryKey: ['usuarios'],
queryFn: () => fetch('/api/usuarios').then(res => res.json())
});
if (isLoading) return <p>Cargando...</p>;
if (error) return <p>Error: {error.message}</p>;
return <ul>{usuarios.map(u => <li key={u.id}>{u.nombre}</li>)}</ul>;
}
// Mutaciones
function FormularioUsuario() {
const queryClient = useQueryClient();
const mutation = useMutation({
mutationFn: (nuevoUsuario) =>
fetch('/api/usuarios', {
method: 'POST',
body: JSON.stringify(nuevoUsuario)
}),
onSuccess: () => {
// Invalida y refresca la lista de usuarios
queryClient.invalidateQueries({ queryKey: ['usuarios'] });
}
});
return (
<button onClick={() => mutation.mutate({ nombre: 'Nuevo' })}>
{mutation.isPending ? 'Creando...' : 'Crear'}
</button>
);
}
Ventajas de React Query
- Cache automatico: Evita peticiones duplicadas
- Revalidacion: Datos frescos automaticamente
- Manejo de errores: Reintentos automaticos
- Estados de carga: isLoading, isFetching, etc.