Creando un Formulario para Registrar Productos en React

 

Creando un Formulario para Registrar Productos en React

En este post para tu blog, te mostraré cómo crear un formulario en React para registrar nuevos productos con campos como id, nombre, descripción y precio, que luego podrás enviar a una API.

Estructura Básica del Formulario

Primero, creemos el componente básico del formulario:

jsx
Copy
Download
import React, { useState } from 'react';

const FormularioProducto = () => {
  const [producto, setProducto] = useState({
    id: '',
    nombre: '',
    descripcion: '',
    precio: ''
  });

  const [mensaje, setMensaje] = useState('');
  const [error, setError] = useState('');

  const handleChange = (e) => {
    const { name, value } = e.target;
    setProducto({
      ...producto,
      [name]: value
    });
  };

  const handleSubmit = async (e) => {
    e.preventDefault();
    
    // Validación básica
    if (!producto.nombre || !producto.precio) {
      setError('Nombre y precio son campos obligatorios');
      return;
    }

    // Aquí iría la lógica para enviar a la API
    console.log('Producto a enviar:', producto);
    setMensaje('Producto registrado correctamente (simulación)');
    setError('');
    
    // Limpiar formulario después de enviar
    setProducto({
      id: '',
      nombre: '',
      descripcion: '',
      precio: ''
    });
  };

  return (
    <div className="form-container">
      <h2>Registrar Nuevo Producto</h2>
      
      {error && <div className="error-message">{error}</div>}
      {mensaje && <div className="success-message">{mensaje}</div>}
      
      <form onSubmit={handleSubmit}>
        <div className="form-group">
          <label htmlFor="id">ID:</label>
          <input
            type="text"
            id="id"
            name="id"
            value={producto.id}
            onChange={handleChange}
            placeholder="Ej: 1001"
          />
        </div>
        
        <div className="form-group">
          <label htmlFor="nombre">Nombre*:</label>
          <input
            type="text"
            id="nombre"
            name="nombre"
            value={producto.nombre}
            onChange={handleChange}
            required
            placeholder="Ej: Laptop Pro"
          />
        </div>
        
        <div className="form-group">
          <label htmlFor="descripcion">Descripción:</label>
          <textarea
            id="descripcion"
            name="descripcion"
            value={producto.descripcion}
            onChange={handleChange}
            placeholder="Ej: Laptop de última generación..."
            rows="3"
          />
        </div>
        
        <div className="form-group">
          <label htmlFor="precio">Precio*:</label>
          <input
            type="number"
            id="precio"
            name="precio"
            value={producto.precio}
            onChange={handleChange}
            required
            min="0"
            step="0.01"
            placeholder="Ej: 599.99"
          />
        </div>
        
        <button type="submit" className="submit-btn">
          Registrar Producto
        </button>
      </form>
    </div>
  );
};

export default FormularioProducto;

Conexión con una API Real

Ahora, modifiquemos el handleSubmit para enviar los datos a una API real:

jsx
Copy
Download
const handleSubmit = async (e) => {
  e.preventDefault();
  
  // Validación
  if (!producto.nombre || !producto.precio) {
    setError('Nombre y precio son campos obligatorios');
    return;
  }

  try {
    setMensaje('');
    setError('');
    
    const response = await fetch('https://api.ejemplo.com/productos', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify(producto)
    });

    if (!response.ok) {
      throw new Error('Error al registrar el producto');
    }

    const data = await response.json();
    setMensaje(`Producto "${data.nombre}" registrado con ID: ${data.id}`);
    
    // Limpiar formulario
    setProducto({
      id: '',
      nombre: '',
      descripcion: '',
      precio: ''
    });
    
  } catch (err) {
    setError(err.message);
    console.error('Error:', err);
  }
};

Validación Mejorada

Podemos mejorar la validación con un función dedicada:

jsx
Copy
Download
const validarProducto = () => {
  const errores = [];
  
  if (!producto.nombre.trim()) {
    errores.push('El nombre es obligatorio');
  }
  
  if (!producto.precio) {
    errores.push('El precio es obligatorio');
  } else if (isNaN(Number(producto.precio)) || Number(producto.precio) <= 0) {
    errores.push('El precio debe ser un número positivo');
  }
  
  return errores;
};

// Y en handleSubmit:
const errores = validarProducto();
if (errores.length > 0) {
  setError(errores.join(', '));
  return;
}

Estilos CSS para el Formulario

css
Copy
Download
.form-container {
  max-width: 600px;
  margin: 0 auto;
  padding: 20px;
  background-color: #f9f9f9;
  border-radius: 8px;
  box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}

.form-group {
  margin-bottom: 15px;
}

.form-group label {
  display: block;
  margin-bottom: 5px;
  font-weight: 600;
}

.form-group input,
.form-group textarea {
  width: 100%;
  padding: 8px;
  border: 1px solid #ddd;
  border-radius: 4px;
  font-size: 16px;
}

.form-group textarea {
  resize: vertical;
}

.error-message {
  color: #d32f2f;
  background-color: #fde0e0;
  padding: 10px;
  border-radius: 4px;
  margin-bottom: 15px;
}

.success-message {
  color: #388e3c;
  background-color: #e8f5e9;
  padding: 10px;
  border-radius: 4px;
  margin-bottom: 15px;
}

.submit-btn {
  background-color: #4caf50;
  color: white;
  padding: 10px 15px;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  font-size: 16px;
  transition: background-color 0.3s;
}

.submit-btn:hover {
  background-color: #388e3c;
}

Funcionalidades Adicionales (Opcional)

Puedes añadir estas mejoras:

  1. Generación automática de ID:

jsx
Copy
Download
useEffect(() => {
  if (!producto.id) {
    // Simular generación de ID (en realidad lo haría el backend)
    setProducto(prev => ({
      ...prev,
      id: Math.floor(Math.random() * 10000).toString()
    }));
  }
}, []);
  1. Modo Edición:

jsx
Copy
Download
const [modoEdicion, setModoEdicion] = useState(false);

// Y modificar handleSubmit para usar PUT en edición
method: modoEdicion ? 'PUT' : 'POST',
  1. Previsualización del Producto:

jsx
Copy
Download
<div className="preview-section">
  <h3>Vista Previa</h3>
  <p><strong>Nombre:</strong> {producto.nombre || 'N/A'}</p>
  <p><strong>Descripción:</strong> {producto.descripcion || 'N/A'}</p>
  <p><strong>Precio:</strong> {producto.precio ? `$${producto.precio}` : 'N/A'}</p>
</div>

Conclusión

Este formulario permite:

  1. Capturar datos de productos de manera estructurada

  2. Validar los campos antes de enviar

  3. Enviar los datos a una API REST

  4. Mostrar feedback al usuario

  5. Manejar errores adecuadamente

Puedes extender este ejemplo añadiendo más campos, subida de imágenes, autocompletado, o integración con bibliotecas de formularios como Formik.

Comentarios

Entradas más populares de este blog

10-2-formulario

10-3-Formulario

10-0Formulario Minimalista con React (Solo Nombre)