TechLead

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.