Módulo 4: Events And Handlers
El objeto evento: `e.target.value` y `preventDefault`
Descripción
Ya sabes conectar un handler (lección 2) y pasarlo bien, sin llamarlo (lección 3). Falta la otra mitad de la conversación: cuando React por fin dispara tu handler, le pasa algo —un argumento—. Ese argumento es el objeto evento, y trae toda la información sobre lo que acaba de pasar: qué elemento lo originó, qué texto hay en un input, qué tecla se presionó. Esta lección abre ese objeto, muestra que es un objeto de JavaScript común y corriente, y te enseña sus dos usos que aparecen en cada formulario: leer el valor de un input con e.target.value y frenar el comportamiento por defecto del navegador con e.preventDefault().
Conexión con el módulo. El objeto evento es lo que hace útiles a onChange y onSubmit, los eventos que gobiernan la SearchBar. Esta lección es la base directa de la lección 5 (inputs controlados: el onChange lee e.target.value para actualizar el estado) y de la lección 7 (el onSubmit de un formulario, que empieza con e.preventDefault()). Sin entender el objeto evento, esos patrones se ven como fórmulas mágicas; con él, se leen palabra por palabra.
Una analogía: la nota que trae el mensajero
Piensa en un mensajero que toca a tu puerta. No llega con las manos vacías: te entrega un sobre con los detalles del encargo —de quién viene, qué contiene, a qué hora llegó—. Tú abres el sobre y lees solo lo que te interesa: si esperabas un paquete, miras el remitente; si es una factura, miras el monto. El sobre siempre llega con el mensajero; qué lees de él depende de lo que necesitas.
El objeto evento es ese sobre. Cuando ocurre un evento, React llama a tu handler y le entrega, como primer argumento, un objeto lleno de detalles: e (por event). De ese objeto lees solo lo que te interesa. Si es un onChange de un input, lees e.target.value —el texto que hay ahora en el campo—: el remitente del sobre es el input, y su "contenido" es lo tecleado. Si es un onSubmit de un formulario, usas e.preventDefault() —una instrucción que viene en el sobre— para decirle al navegador "no hagas lo que harías normalmente". El sobre siempre llega; tú decides qué sacar de él.
Y un matiz de la analogía que aclara preventDefault: algunos encargos traen un comportamiento por defecto que se dispara solo si no dices nada. Un formulario, por defecto, recarga la página al enviarse (una herencia de la web de los años 90, cuando enviar un <form> mandaba todo al servidor y traía una página nueva). En una app de React eso es un desastre: recargar borra el estado y reinicia todo. e.preventDefault() es la nota dentro del sobre que dice "esta vez, no recargues": frena el comportamiento por defecto y deja que tu código maneje el envío.
Ejemplo trabajado: leer el input y frenar el submit
Vamos a modelar los dos usos del objeto evento, ejecutados. La clave conceptual es que el objeto evento es un objeto normal de JavaScript: React lo construye y se lo pasa al handler, pero no tiene nada de mágico, así que podemos modelarlo con un objeto que armamos a mano. Para onChange, el objeto trae target.value (el texto del input). Para onSubmit, trae un método preventDefault() que, al llamarse, levanta una bandera defaultPrevented.
// React le pasa a cada handler un OBJETO EVENTO. Lo modelamos como un objeto normal.
// === onChange: el handler recibe un evento; el texto esta en e.target.value ===
function handleChange(e) {
console.log(` handleChange: el usuario escribio "${e.target.value}"`);
}
const changeEvent = { target: { value: 'mouse' } }; // React arma esto por ti
console.log('El usuario teclea en el input...');
handleChange(changeEvent);
// === onSubmit: preventDefault frena la recarga de la pagina ===
function handleSubmit(e) {
e.preventDefault();
console.log(' handleSubmit: enviado SIN recargar la pagina');
}
function makeSubmitEvent() {
return { defaultPrevented: false, preventDefault() { this.defaultPrevented = true; } };
}
console.log('\nEl usuario envia el formulario...');
const submitEvent = makeSubmitEvent();
console.log('antes del handler -> defaultPrevented:', submitEvent.defaultPrevented);
handleSubmit(submitEvent);
console.log('despues del handler -> defaultPrevented:', submitEvent.defaultPrevented);
console.log('El navegador ve defaultPrevented=true y NO recarga.');
Qué esperar. Al correr el archivo con Node, la salida es exactamente esta:
El usuario teclea en el input...
handleChange: el usuario escribio "mouse"
El usuario envia el formulario...
antes del handler -> defaultPrevented: false
handleSubmit: enviado SIN recargar la pagina
despues del handler -> defaultPrevented: true
El navegador ve defaultPrevented=true y NO recarga.
Lee las dos mitades.
La primera es onChange. El "input" cambió, React armó un objeto evento con target.value = 'mouse' (el texto que hay ahora en el campo) y llamó a handleChange(e). El handler leyó e.target.value y supo que el usuario escribió "mouse". Nota la ruta: e es el sobre; e.target es el elemento que originó el evento (el <input>); e.target.value es el valor de ese input. Esa cadena, e.target.value, es la que usarás en cada onChange para saber qué hay escrito.
La segunda es onSubmit, y observa la bandera defaultPrevented cambiar. Antes del handler vale false: el navegador recargaría la página si nadie dice lo contrario. El handler llama a e.preventDefault(), que levanta la bandera. Después vale true. Con la bandera en true, el navegador ve que alguien pidió frenar el comportamiento por defecto y no recarga: deja que el resto del handler maneje el envío. En una app real, ese "resto" sería avisar al padre qué se buscó (la lección 7); aquí lo modelamos con el mensaje enviado SIN recargar la pagina. La lección visible: e.preventDefault() es una instrucción que sacas del sobre para cambiar el comportamiento por defecto del navegador.
Profundización: el objeto evento por dentro
e.target vs e.currentTarget. e.target es el elemento donde se originó el evento —el input que cambió, el botón exacto en el que se hizo clic—. e.currentTarget es el elemento al que le conectaste el handler. Casi siempre son el mismo, y en el storefront no vas a notar la diferencia; pero si conectas un onClick a un <div> que contiene un <button>, y el usuario hace clic en el botón, e.target es el botón y e.currentTarget es el div. Para leer el valor de un input en su propio onChange, e.target.value es lo correcto: el input es a la vez el origen y el elemento con el handler.
e.target.value es siempre un string. Aunque el input sea de tipo número, e.target.value te da el texto ("25", no 25). Si necesitas el número, conviértelo tú (Number(e.target.value)). Para la SearchBar, que trabaja con texto, esto no molesta; tenlo presente para inputs numéricos.
Los eventos por defecto que vas a querer frenar. No solo el submit de un formulario. Otros comportamientos por defecto comunes:
Elemento / evento Comportamiento por defecto Cuando lo frenas
───────────────────────── ──────────────────────────────── ──────────────────────────
<form> onSubmit recarga la pagina (GET/POST) casi siempre en una SPA
<a href="..."> onClick navega a otra pagina si manejas la navegacion tu
<input> ... (algunas) comportamientos del navegador casos puntuales
En este módulo el caso que importa es el <form>: siempre que uses un <form onSubmit> en React, tu handler empieza con e.preventDefault(), o la página se recargará y perderás el estado.
Por qué un <form> y no solo un <input> con un botón. Podrías capturar la búsqueda con un <input> y un <button onClick>. Pero un <form> te da algo gratis: el usuario puede presionar Enter dentro del input y eso dispara onSubmit. Es la expectativa de cualquiera que usa un buscador. Por eso la SearchBar de la lección 7 será un <form onSubmit={handleSubmit}> con e.preventDefault(): obtienes el Enter gratis y frenas la recarga.
Los eventos sintéticos de React (mención). El objeto e que recibes no es exactamente el evento nativo del navegador: React lo envuelve en un objeto propio llamado SyntheticEvent, que normaliza las diferencias entre navegadores para que e.target, e.preventDefault(), etc., funcionen igual en todos. Para tu día a día es transparente —lo usas igual que el nativo—; solo tenlo como dato, y si alguna vez necesitas el evento nativo real, está en e.nativeEvent. La doc oficial de React lo detalla (enlace en Recursos).
Errores comunes
Olvidar e.preventDefault() en el onSubmit. Qué pasa: al enviar el formulario, la página se recarga —parpadea, se reinicia, y todo el estado (la búsqueda, el carrito) se pierde—. Por qué pasa: el comportamiento por defecto de un <form> es recargar, y es fácil olvidar que hay que frenarlo. Cómo detectarlo: presionas Enter o el botón de submit y la app "se reinicia sola"; en la consola del navegador ves una recarga. Cómo corregirlo: la primera línea de todo handler de submit es e.preventDefault();. Si tu handler no recibe e, agrégalo: function handleSubmit(e) { e.preventDefault(); ... }.
Leer el valor del sitio equivocado (e.value en vez de e.target.value). Qué pasa: se escribe e.value y sale undefined. Por qué pasa: se olvida el paso intermedio .target. Cómo detectarlo: el texto tecleado aparece como undefined en tu handler. Cómo corregirlo: el valor no está en el evento directamente, sino en el elemento que originó el evento: e.target.value. El evento es el sobre; el input es e.target; el texto es su .value.
Nombrar mal (o no recibir) el parámetro del evento. Qué pasa: se define function handleChange() {...} sin parámetro y luego se intenta usar e adentro —e is not defined—. Por qué pasa: se olvida que React pasa el evento como argumento, y hay que recibirlo. Cómo detectarlo: un ReferenceError: e is not defined dentro del handler. Cómo corregirlo: declara el parámetro: function handleChange(e) {...} o (e) => .... El nombre e es solo convención (podría ser event); lo que importa es recibir el primer argumento que React entrega.
Ejercicios
Ejercicio 1 — Saca el dato del sobre. Este handler quiere imprimir lo que el usuario tecleó, pero está incompleto. Complétalo:
function handleChange(e) {
console.log('El usuario escribió:', /* ??? */);
}
Si el usuario tecleó keyboard, ¿qué imprime tu versión?
Ver solución
El texto tecleado está en e.target.value:
function handleChange(e) {
console.log('El usuario escribió:', e.target.value);
}
Si el usuario tecleó keyboard, React arma un evento con target.value = 'keyboard', y el handler imprime:
El usuario escribió: keyboard
La ruta completa: e (el sobre) → e.target (el <input> que originó el cambio) → e.target.value (el texto que hay en él). Recuerda que siempre es un string, aunque el input sea numérico.
Ejercicio 2 — El formulario que se recarga. Este onSubmit no funciona: al enviar, la página se recarga y se pierde todo. Explica por qué y corrígelo:
function SearchBar() {
function handleSubmit() {
console.log('Buscando...');
}
return (
<form onSubmit={handleSubmit}>
<input />
<button type="submit">Search</button>
</form>
);
}
Ver solución
El problema es que handleSubmit no frena el comportamiento por defecto del <form>, que es recargar la página. El console.log alcanza a correr, pero un instante después el navegador recarga y todo se reinicia.
Corrección: recibir el evento y llamar a e.preventDefault() como primera línea.
function SearchBar() {
function handleSubmit(e) {
e.preventDefault(); // frena la recarga por defecto del <form>
console.log('Buscando...');
}
return (
<form onSubmit={handleSubmit}>
<input />
<button type="submit">Search</button>
</form>
);
}
Ahora, al enviar (con el botón o presionando Enter en el input), el handler frena la recarga y maneja la búsqueda con tu propio código, sin perder el estado.
Ejercicio 3 — Traza la bandera. Usando el modelo del ejemplo trabajado, ¿qué imprime este código? Explica cada línea.
function makeSubmitEvent() {
return { defaultPrevented: false, preventDefault() { this.defaultPrevented = true; } };
}
const e = makeSubmitEvent();
console.log(e.defaultPrevented);
e.preventDefault();
console.log(e.defaultPrevented);
Ver solución
Imprime:
false
true
- La primera línea,
console.log(e.defaultPrevented), imprimefalse: el evento recién creado no ha sido "prevenido" —el navegador recargaría—. e.preventDefault()ejecuta el método, que hacethis.defaultPrevented = true—levanta la bandera—.- La segunda línea imprime
true: ahora el evento está marcado como prevenido, y el navegador (que revisa esa bandera) no ejecutará su comportamiento por defecto.
Este modelo es exactamente lo que hace el navegador real: preventDefault() marca el evento, y el navegador consulta esa marca para decidir si dispara o no su comportamiento por defecto (la recarga, la navegación, etc.).
Resumen y siguiente paso
En esta lección abriste el objeto evento: el argumento que React le pasa a tu handler cuando dispara el evento —el "sobre" con los detalles de lo que pasó—. Es un objeto de JavaScript normal, y de él usas, sobre todo, dos cosas. e.target.value: el texto que hay en el input que originó el evento (el origen es e.target, su contenido es .value, y siempre es un string). e.preventDefault(): la instrucción para frenar el comportamiento por defecto del navegador —crucial en un <form onSubmit>, que si no se frena recarga la página y borra el estado—. Lo mediste ejecutando: un onChange que sacó "mouse" de e.target.value, y un onSubmit donde preventDefault() levantó la bandera defaultPrevented de false a true, para que el navegador no recargara.
Antes de avanzar deberías poder: explicar qué es el objeto evento y por qué el handler debe recibirlo como parámetro; leer el texto de un input con e.target.value; y frenar la recarga de un formulario con e.preventDefault().
La lección 5 junta todo lo del módulo hasta aquí en el patrón más importante de los formularios en React: los inputs controlados. Vas a construir la SearchBar cuyo value sale del estado y cuyo onChange lo actualiza —usando el e.target.value que acabas de aprender—, cerrando un bucle donde el estado es la única fuente de verdad. Y lo verás ejecutado letra por letra, mientras se teclea una palabra.
Recursos
- React, "Responding to Events" — react.dev/learn/responding-to-events. Introduce el objeto evento,
e.preventDefault()y cómo los handlers reciben el evento. En inglés. - React, "React DOM Components: Common (SyntheticEvent)" — react.dev/reference/react-dom/components/common#react-event-object. La referencia del objeto evento de React (SyntheticEvent): sus propiedades (
target,currentTarget), sus métodos (preventDefault,stopPropagation) ynativeEvent. En inglés. - MDN, "Event" — developer.mozilla.org/en-US/docs/Web/API/Event. La interfaz
Eventdel DOM que React envuelve: qué estarget, qué hacepreventDefault(), el modelo de eventos del navegador. En inglés. - MDN, "Event: preventDefault() method" — developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault. La página puntual sobre
preventDefault(): qué comportamientos por defecto frena y cómo. En inglés.