En casi cualquier aplicación moderna, interactuar con APIs es fundamental. Desde obtener datos de usuarios hasta enviar información a un servidor, manejar las llamadas a APIs de manera correcta en React garantiza aplicaciones más confiables, rápidas y fáciles de mantener.

En este tutorial aprenderás cómo realizar llamadas a APIs, manejar estados de carga y error, optimizar las peticiones y utilizar herramientas modernas como React Query para simplificar el trabajo con datos remotos.
Cómo hacer llamadas a APIs en React
En React, las llamadas a APIs suelen realizarse dentro de efectos usando el Hook useEffect. Esto permite que la petición se ejecute en momentos específicos del ciclo de vida del componente, como cuando se monta por primera vez.
Ejemplo básico usando fetch
import { useState, useEffect } from "react";
function Usuarios() {
const [usuarios, setUsuarios] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
fetch("https://api.example.com/users")
.then((res) => res.json())
.then((data) => {
setUsuarios(data);
setLoading(false);
})
.catch((err) => {
setError(err);
setLoading(false);
});
}, []);
if (loading) return <p>Cargando...</p>;
if (error) return <p>Error: {error.message}</p>;
return (
<ul>
{usuarios.map((user) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
}
En este ejemplo:
useEffectse ejecuta una sola vez al montar el componente.- Se manejan los estados de
loadingyerror. - Los datos obtenidos se almacenan en el estado local
usuarios.
Manejo de múltiples llamadas y dependencias
Si necesitas realizar varias llamadas o que dependa de variables, simplemente ajusta el array de dependencias del useEffect.
useEffect(() => {
fetch(`https://api.example.com/users?rol=${rol}`)
.then((res) => res.json())
.then(setUsuarios)
.catch(setError);
}, [rol]);
Cada vez que rol cambie, se ejecutará la llamada nuevamente.
Optimización de peticiones
- AbortController: Cancela peticiones si el componente se desmonta antes de recibir la respuesta.
- Debounce: Evita realizar llamadas demasiado frecuentes, ideal para búsquedas en tiempo real.
- Cacheo: Reutiliza datos previamente obtenidos en lugar de llamar a la API constantemente.
Ejemplo con AbortController
useEffect(() => {
const controller = new AbortController();
fetch("https://api.example.com/users", { signal: controller.signal })
.then((res) => res.json())
.then(setUsuarios)
.catch((err) => {
if (err.name !== "AbortError") setError(err);
});
return () => controller.abort();
}, []);
Usando librerías especializadas: React Query
React Query simplifica enormemente el manejo de datos remotos:
- Maneja automáticamente estados de carga y error
- Cachea los resultados
- Actualiza datos en segundo plano
- Permite reintentos y paginación de manera sencilla
Ejemplo con React Query
import { useQuery } from "@tanstack/react-query";
function Usuarios() {
const { data, error, isLoading } = useQuery(["usuarios"], () =>
fetch("https://api.example.com/users").then((res) => res.json())
);
if (isLoading) return <p>Cargando...</p>;
if (error) return <p>Error: {error.message}</p>;
return (
<ul>
{data.map((user) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
}
React Query elimina mucho del código repetitivo que se necesita al usar useEffect y useState, mejorando la organización y la eficiencia del proyecto.
Buenas prácticas al trabajar con APIs en React
- Siempre maneja estados de carga y error.
- Evita realizar llamadas dentro del render.
- Usa librerías como React Query cuando la aplicación sea compleja.
- Divide la lógica de llamadas en servicios o hooks personalizados para mantener el código limpio.
- Implementa cacheo o debounce si trabajas con datos que cambian constantemente.

Ingeniero en Informática, Investigador, me encanta crear cosas o arreglarlas y darles una nueva vida. Escritor y poeta. Más de 20 APPs publicadas y un libro en Amazon.