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:
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:
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:
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
.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:
Generación automática de ID:
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()
}));
}
}, []);Modo Edición:
const [modoEdicion, setModoEdicion] = useState(false);
// Y modificar handleSubmit para usar PUT en edición
method: modoEdicion ? 'PUT' : 'POST',Previsualización del Producto:
<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:
Capturar datos de productos de manera estructurada
Validar los campos antes de enviar
Enviar los datos a una API REST
Mostrar feedback al usuario
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
Publicar un comentario