Ejemplo de React consumiendo API de productos (versión mock y real)

  

Ejemplo de React consumiendo API de productos (versión mock y real)

Aquí te presento un componente React que muestra productos en cards de Bootstrap, con dos versiones: una usando datos mockeados y otra consumiendo un endpoint real.

Versión completa con ambas implementaciones

jsx
Copy
Download
import React, { useState, useEffect } from 'react';
import { Card, Container, Row, Col, Spinner } from 'react-bootstrap';

const ProductosApp = () => {
  const [modo, setModo] = useState('mock'); // 'mock' o 'api'
  const [productos, setProductos] = useState([]);
  const [cargando, setCargando] = useState(false);
  const [error, setError] = useState(null);

  // Datos mockeados
  const datosMock = [
    { articulo: 'P001', descripcion: 'Laptop HP EliteBook', precio: 1250.99 },
    { articulo: 'P002', descripcion: 'Teclado mecánico RGB', precio: 89.50 },
    { articulo: 'P003', descripcion: 'Mouse inalámbrico', precio: 35.20 },
    { articulo: 'P004', descripcion: 'Monitor 24" Full HD', precio: 199.99 },
  ];

  // Función para cargar productos mockeados
  const cargarMock = () => {
    setCargando(true);
    setTimeout(() => {
      setProductos(datosMock);
      setCargando(false);
    }, 1000); // Simulamos delay de red
  };

  // Función para cargar productos desde API real
  const cargarDesdeAPI = async () => {
    setCargando(true);
    setError(null);
    try {
      const response = await fetch('https://api.ejemplo.com/productos');
      if (!response.ok) {
        throw new Error('Error al obtener productos');
      }
      const data = await response.json();
      setProductos(data);
    } catch (err) {
      setError(err.message);
      console.error('Error:', err);
    } finally {
      setCargando(false);
    }
  };

  useEffect(() => {
    if (modo === 'mock') {
      cargarMock();
    } else {
      cargarDesdeAPI();
    }
  }, [modo]);

  return (
    <Container className="mt-5">
      <h1 className="mb-4">Catálogo de Productos</h1>
      
      <div className="mb-4">
        <button 
          className={`btn ${modo === 'mock' ? 'btn-primary' : 'btn-outline-primary'} me-2`}
          onClick={() => setModo('mock')}
        >
          Versión Mock
        </button>
        <button 
          className={`btn ${modo === 'api' ? 'btn-primary' : 'btn-outline-primary'}`}
          onClick={() => setModo('api')}
        >
          Versión API Real
        </button>
      </div>

      {error && (
        <div className="alert alert-danger">
          Error: {error}. {modo === 'api' && '¿Estás seguro que la API está disponible?'}
        </div>
      )}

      {cargando ? (
        <div className="text-center">
          <Spinner animation="border" role="status">
            <span className="visually-hidden">Cargando...</span>
          </Spinner>
          <p>Cargando productos...</p>
        </div>
      ) : (
        <Row xs={1} md={2} lg={3} className="g-4">
          {productos.map((producto) => (
            <Col key={producto.articulo}>
              <Card className="h-100">
                <Card.Body>
                  <Card.Title>{producto.articulo}</Card.Title>
                  <Card.Subtitle className="mb-2 text-muted">
                    ${producto.precio.toFixed(2)}
                  </Card.Subtitle>
                  <Card.Text>{producto.descripcion}</Card.Text>
                </Card.Body>
                <Card.Footer>
                  <button className="btn btn-sm btn-outline-success">
                    Agregar al carrito
                  </button>
                </Card.Footer>
              </Card>
            </Col>
          ))}
        </Row>
      )}
    </Container>
  );
};

export default ProductosApp;

Versión solo con datos mockeados (simplificada)

jsx
Copy
Download
import React from 'react';
import { Card, Container, Row, Col } from 'react-bootstrap';

const ProductosMock = () => {
  const productos = [
    { articulo: 'P001', descripcion: 'Laptop HP EliteBook', precio: 1250.99 },
    { articulo: 'P002', descripcion: 'Teclado mecánico RGB', precio: 89.50 },
    { articulo: 'P003', descripcion: 'Mouse inalámbrico', precio: 35.20 },
    { articulo: 'P004', descripcion: 'Monitor 24" Full HD', precio: 199.99 },
  ];

  return (
    <Container className="mt-5">
      <h1 className="mb-4">Productos (Datos Mock)</h1>
      <Row xs={1} md={2} lg={3} className="g-4">
        {productos.map((producto) => (
          <Col key={producto.articulo}>
            <Card className="h-100">
              <Card.Body>
                <Card.Title>{producto.articulo}</Card.Title>
                <Card.Subtitle className="mb-2 text-muted">
                  ${producto.precio.toFixed(2)}
                </Card.Subtitle>
                <Card.Text>{producto.descripcion}</Card.Text>
              </Card.Body>
              <Card.Footer>
                <button className="btn btn-sm btn-outline-success">
                  Agregar al carrito
                </button>
              </Card.Footer>
            </Card>
          </Col>
        ))}
      </Row>
    </Container>
  );
};

export default ProductosMock;

Versión solo con API real (simplificada)

jsx
Copy
Download
import React, { useState, useEffect } from 'react';
import { Card, Container, Row, Col, Spinner } from 'react-bootstrap';

const ProductosAPI = () => {
  const [productos, setProductos] = useState([]);
  const [cargando, setCargando] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    const fetchProductos = async () => {
      try {
        const response = await fetch('https://api.ejemplo.com/productos');
        if (!response.ok) {
          throw new Error('Error al obtener productos');
        }
        const data = await response.json();
        setProductos(data);
      } catch (err) {
        setError(err.message);
        console.error('Error:', err);
      } finally {
        setCargando(false);
      }
    };

    fetchProductos();
  }, []);

  if (cargando) {
    return (
      <Container className="mt-5 text-center">
        <Spinner animation="border" role="status">
          <span className="visually-hidden">Cargando...</span>
        </Spinner>
        <p>Cargando productos...</p>
      </Container>
    );
  }

  if (error) {
    return (
      <Container className="mt-5">
        <div className="alert alert-danger">
          Error: {error}. ¿Estás seguro que la API está disponible?
        </div>
      </Container>
    );
  }

  return (
    <Container className="mt-5">
      <h1 className="mb-4">Productos (API Real)</h1>
      <Row xs={1} md={2} lg={3} className="g-4">
        {productos.map((producto) => (
          <Col key={producto.articulo}>
            <Card className="h-100">
              <Card.Body>
                <Card.Title>{producto.articulo}</Card.Title>
                <Card.Subtitle className="mb-2 text-muted">
                  ${producto.precio.toFixed(2)}
                </Card.Subtitle>
                <Card.Text>{producto.descripcion}</Card.Text>
              </Card.Body>
              <Card.Footer>
                <button className="btn btn-sm btn-outline-success">
                  Agregar al carrito
                </button>
              </Card.Footer>
            </Card>
          </Col>
        ))}
      </Row>
    </Container>
  );
};

export default ProductosAPI;

Características destacadas:

  1. Versión mock:

    • No requiere backend

    • Datos estáticos para desarrollo rápido

    • Útil para pruebas y prototipos

  2. Versión API real:

    • Manejo de estados de carga

    • Manejo de errores

    • Uso de useEffect para el fetch de datos

    • Estructura async/await moderna

  3. UI consistente:

    • Cards responsive con Bootstrap

    • Formato de precio consistente

    • Diseño limpio y profesional

Para usar estos componentes, necesitarás instalar las dependencias de Bootstrap:

bash
Copy
Download
npm install react-bootstrap bootstrap

Comentarios

Entradas más populares de este blog

10-2-formulario

10-3-Formulario

10-0Formulario Minimalista con React (Solo Nombre)