Skip to content

6. Eventos y Formularios

🎯 6.1 Eventos en React (onClick, onChange, onSubmit)

Section titled “🎯 6.1 Eventos en React (onClick, onChange, onSubmit)”

En React, los eventos se escriben en camelCase y reciben una función como valor.

HTMLReact
onclickonClick
onchangeonChange
onsubmitonSubmit
onmouseoveronMouseOver
onkeydownonKeyDown
Evento onClick
function Boton() {
// Función manejadora
const handleClick = () => {
alert("¡Botón clickeado!");
};
return (
<button onClick={handleClick}>
Haz clic
</button>
);
}
// También puedes usar función inline
function Boton() {
return (
<button onClick={() => alert("¡Clic!")}>
Haz clic
</button>
);
}
Evento onChange
import { useState } from 'react';
function InputTexto() {
const [texto, setTexto] = useState("");
const handleChange = (event) => {
setTexto(event.target.value);
};
return (
<div>
<input
type="text"
value={texto}
onChange={handleChange}
/>
<p>Escribiste: {texto}</p>
</div>
);
}
Evento onSubmit
import { useState } from 'react';
function Formulario() {
const [nombre, setNombre] = useState("");
const handleSubmit = (event) => {
event.preventDefault(); // Evita recargar la página
console.log("Enviado:", nombre);
};
return (
<form onSubmit={handleSubmit}>
<input
value={nombre}
onChange={(e) => setNombre(e.target.value)}
/>
<button type="submit">Enviar</button>
</form>
);
}

Objeto event
function ManejoEvento() {
const handleClick = (event) => {
// Propiedades útiles del evento
console.log(event.target); // Elemento que disparó el evento
console.log(event.target.value); // Valor del elemento (inputs)
console.log(event.type); // Tipo de evento ("click")
console.log(event.clientX); // Posición X del mouse
console.log(event.clientY); // Posición Y del mouse
};
return <button onClick={handleClick}>Clic</button>;
}
Pasar parámetros
function Lista() {
const items = ["Manzana", "Banana", "Naranja"];
// ❌ MAL - Se ejecuta inmediatamente
const handleClick = (item) => {
console.log(item);
};
// <button onClick={handleClick(item)}> // Error
// ✅ BIEN - Usa arrow function
return (
<ul>
{items.map((item, index) => (
<li key={index}>
{item}
<button onClick={() => handleClick(item)}>
Seleccionar
</button>
</li>
))}
</ul>
);
}
Múltiples eventos
function Tarjeta() {
const handleMouseEnter = () => console.log("Mouse entró");
const handleMouseLeave = () => console.log("Mouse salió");
const handleDoubleClick = () => console.log("Doble clic");
return (
<div
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
onDoubleClick={handleDoubleClick}
style={{ padding: "20px", border: "1px solid #ccc" }}
>
Pasa el mouse o haz doble clic
</div>
);
}

Un input controlado es aquel cuyo valor está controlado por el estado de React. El estado es la “fuente de verdad”.

Input controlado vs no controlado
import { useState } from 'react';
// Input CONTROLADO
function InputControlado() {
const [valor, setValor] = useState("");
return (
<input
value={valor} // Valor del estado
onChange={(e) => setValor(e.target.value)} // Actualiza estado
/>
);
}
// Input NO controlado (evitar)
function InputNoControlado() {
return <input />; // React no controla el valor
}
Tipos de inputs
import { useState } from 'react';
function FormularioCompleto() {
const [texto, setTexto] = useState("");
const [numero, setNumero] = useState(0);
const [seleccion, setSeleccion] = useState("opcion1");
const [checkbox, setCheckbox] = useState(false);
const [textarea, setTextarea] = useState("");
return (
<form>
{/* Input de texto */}
<input
type="text"
value={texto}
onChange={(e) => setTexto(e.target.value)}
/>
{/* Input numérico */}
<input
type="number"
value={numero}
onChange={(e) => setNumero(Number(e.target.value))}
/>
{/* Select */}
<select
value={seleccion}
onChange={(e) => setSeleccion(e.target.value)}
>
<option value="opcion1">Opción 1</option>
<option value="opcion2">Opción 2</option>
<option value="opcion3">Opción 3</option>
</select>
{/* Checkbox */}
<input
type="checkbox"
checked={checkbox}
onChange={(e) => setCheckbox(e.target.checked)}
/>
{/* Textarea */}
<textarea
value={textarea}
onChange={(e) => setTextarea(e.target.value)}
/>
</form>
);
}

Formulario de contacto
import { useState } from 'react';
function FormularioContacto() {
const [nombre, setNombre] = useState("");
const [email, setEmail] = useState("");
const [mensaje, setMensaje] = useState("");
const handleSubmit = (e) => {
e.preventDefault();
const datos = { nombre, email, mensaje };
console.log("Datos enviados:", datos);
// Limpiar formulario
setNombre("");
setEmail("");
setMensaje("");
};
return (
<form onSubmit={handleSubmit}>
<div>
<label>Nombre:</label>
<input
type="text"
value={nombre}
onChange={(e) => setNombre(e.target.value)}
/>
</div>
<div>
<label>Email:</label>
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
</div>
<div>
<label>Mensaje:</label>
<textarea
value={mensaje}
onChange={(e) => setMensaje(e.target.value)}
/>
</div>
<button type="submit">Enviar</button>
</form>
);
}
Formulario con objeto
import { useState } from 'react';
function FormularioRegistro() {
const [formData, setFormData] = useState({
nombre: "",
email: "",
password: "",
edad: 18
});
const handleChange = (e) => {
const { name, value, type } = e.target;
setFormData(prev => ({
...prev,
[name]: type === "number" ? Number(value) : value
}));
};
const handleSubmit = (e) => {
e.preventDefault();
console.log("Registro:", formData);
};
return (
<form onSubmit={handleSubmit}>
<input
name="nombre"
placeholder="Nombre"
value={formData.nombre}
onChange={handleChange}
/>
<input
name="email"
type="email"
placeholder="Email"
value={formData.email}
onChange={handleChange}
/>
<input
name="password"
type="password"
placeholder="Contraseña"
value={formData.password}
onChange={handleChange}
/>
<input
name="edad"
type="number"
value={formData.edad}
onChange={handleChange}
/>
<button type="submit">Registrar</button>
</form>
);
}

Validación en tiempo real
import { useState } from 'react';
function FormularioValidado() {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [errores, setErrores] = useState({});
const validarEmail = (valor) => {
if (!valor) return "El email es requerido";
if (!valor.includes("@")) return "Email inválido";
return "";
};
const validarPassword = (valor) => {
if (!valor) return "La contraseña es requerida";
if (valor.length < 6) return "Mínimo 6 caracteres";
return "";
};
const handleEmailChange = (e) => {
const valor = e.target.value;
setEmail(valor);
setErrores(prev => ({
...prev,
email: validarEmail(valor)
}));
};
const handlePasswordChange = (e) => {
const valor = e.target.value;
setPassword(valor);
setErrores(prev => ({
...prev,
password: validarPassword(valor)
}));
};
return (
<form>
<div>
<input
type="email"
value={email}
onChange={handleEmailChange}
placeholder="Email"
/>
{errores.email && (
<span style={{ color: "red" }}>{errores.email}</span>
)}
</div>
<div>
<input
type="password"
value={password}
onChange={handlePasswordChange}
placeholder="Contraseña"
/>
{errores.password && (
<span style={{ color: "red" }}>{errores.password}</span>
)}
</div>
</form>
);
}
Validación al enviar
import { useState } from 'react';
function FormularioConValidacion() {
const [datos, setDatos] = useState({
nombre: "",
email: "",
edad: ""
});
const [errores, setErrores] = useState({});
const validar = () => {
const nuevosErrores = {};
if (!datos.nombre.trim()) {
nuevosErrores.nombre = "El nombre es requerido";
}
if (!datos.email.includes("@")) {
nuevosErrores.email = "Email inválido";
}
if (datos.edad < 18) {
nuevosErrores.edad = "Debes ser mayor de 18";
}
setErrores(nuevosErrores);
return Object.keys(nuevosErrores).length === 0;
};
const handleSubmit = (e) => {
e.preventDefault();
if (validar()) {
console.log("Formulario válido:", datos);
// Enviar datos...
} else {
console.log("Hay errores");
}
};
const handleChange = (e) => {
const { name, value } = e.target;
setDatos(prev => ({ ...prev, [name]: value }));
};
return (
<form onSubmit={handleSubmit}>
<div>
<input
name="nombre"
value={datos.nombre}
onChange={handleChange}
placeholder="Nombre"
/>
{errores.nombre && <span className="error">{errores.nombre}</span>}
</div>
<div>
<input
name="email"
value={datos.email}
onChange={handleChange}
placeholder="Email"
/>
{errores.email && <span className="error">{errores.email}</span>}
</div>
<div>
<input
name="edad"
type="number"
value={datos.edad}
onChange={handleChange}
placeholder="Edad"
/>
{errores.edad && <span className="error">{errores.edad}</span>}
</div>
<button type="submit">Enviar</button>
</form>
);
}

🚫 6.6 Prevención de comportamiento por defecto

Section titled “🚫 6.6 Prevención de comportamiento por defecto”
preventDefault
// Formulario - evita recargar la página
const handleSubmit = (e) => {
e.preventDefault();
// Tu lógica aquí
};
// Link - evita navegar
const handleLinkClick = (e) => {
e.preventDefault();
console.log("Link clickeado pero no navega");
};
// Ejemplo completo
function Formulario() {
const handleSubmit = (e) => {
e.preventDefault(); // Sin esto, la página se recarga
console.log("Formulario enviado sin recargar");
};
return (
<form onSubmit={handleSubmit}>
<input type="text" />
<button type="submit">Enviar</button>
</form>
);
}
stopPropagation
function Contenedor() {
const handleContainerClick = () => {
console.log("Contenedor clickeado");
};
const handleButtonClick = (e) => {
e.stopPropagation(); // Evita que el evento suba al contenedor
console.log("Solo botón clickeado");
};
return (
<div onClick={handleContainerClick} style={{ padding: "20px", background: "#eee" }}>
<p>Haz clic aquí (contenedor)</p>
<button onClick={handleButtonClick}>
Clic aquí (no propaga)
</button>
</div>
);
}

Handler único
import { useState } from 'react';
function FormularioMultiple() {
const [formData, setFormData] = useState({
nombre: "",
apellido: "",
email: "",
telefono: "",
ciudad: "",
pais: ""
});
// Un solo handler para todos los inputs
const handleChange = (e) => {
const { name, value, type, checked } = e.target;
setFormData(prev => ({
...prev,
[name]: type === "checkbox" ? checked : value
}));
};
const handleSubmit = (e) => {
e.preventDefault();
console.log(formData);
};
return (
<form onSubmit={handleSubmit}>
<input
name="nombre"
placeholder="Nombre"
value={formData.nombre}
onChange={handleChange}
/>
<input
name="apellido"
placeholder="Apellido"
value={formData.apellido}
onChange={handleChange}
/>
<input
name="email"
type="email"
placeholder="Email"
value={formData.email}
onChange={handleChange}
/>
<input
name="telefono"
placeholder="Teléfono"
value={formData.telefono}
onChange={handleChange}
/>
<input
name="ciudad"
placeholder="Ciudad"
value={formData.ciudad}
onChange={handleChange}
/>
<input
name="pais"
placeholder="País"
value={formData.pais}
onChange={handleChange}
/>
<button type="submit">Enviar</button>
</form>
);
}
Formulario completo
import { useState } from 'react';
function FormularioCompleto() {
const [formData, setFormData] = useState({
nombre: "",
email: "",
password: "",
confirmPassword: "",
aceptaTerminos: false
});
const [errores, setErrores] = useState({});
const [enviado, setEnviado] = useState(false);
const handleChange = (e) => {
const { name, value, type, checked } = e.target;
setFormData(prev => ({
...prev,
[name]: type === "checkbox" ? checked : value
}));
};
const validar = () => {
const nuevosErrores = {};
if (!formData.nombre) nuevosErrores.nombre = "Requerido";
if (!formData.email.includes("@")) nuevosErrores.email = "Email inválido";
if (formData.password.length < 6) nuevosErrores.password = "Mínimo 6 caracteres";
if (formData.password !== formData.confirmPassword) {
nuevosErrores.confirmPassword = "Las contraseñas no coinciden";
}
if (!formData.aceptaTerminos) nuevosErrores.aceptaTerminos = "Debes aceptar";
setErrores(nuevosErrores);
return Object.keys(nuevosErrores).length === 0;
};
const handleSubmit = (e) => {
e.preventDefault();
if (validar()) {
console.log("Enviando:", formData);
setEnviado(true);
}
};
if (enviado) {
return <p>¡Registro exitoso!</p>;
}
return (
<form onSubmit={handleSubmit}>
<div>
<input name="nombre" placeholder="Nombre"
value={formData.nombre} onChange={handleChange} />
{errores.nombre && <span className="error">{errores.nombre}</span>}
</div>
<div>
<input name="email" type="email" placeholder="Email"
value={formData.email} onChange={handleChange} />
{errores.email && <span className="error">{errores.email}</span>}
</div>
<div>
<input name="password" type="password" placeholder="Contraseña"
value={formData.password} onChange={handleChange} />
{errores.password && <span className="error">{errores.password}</span>}
</div>
<div>
<input name="confirmPassword" type="password" placeholder="Confirmar"
value={formData.confirmPassword} onChange={handleChange} />
{errores.confirmPassword && <span className="error">{errores.confirmPassword}</span>}
</div>
<div>
<label>
<input name="aceptaTerminos" type="checkbox"
checked={formData.aceptaTerminos} onChange={handleChange} />
Acepto los términos
</label>
{errores.aceptaTerminos && <span className="error">{errores.aceptaTerminos}</span>}
</div>
<button type="submit">Registrar</button>
</form>
);
}

🐝