React maneja los eventos con props que llevan el nombre del evento en camelCase, como onClick, onChange y onSubmit. Pasas una función, y React la llama con un objeto de evento cuando el usuario hace clic, escribe o envía.
Cada clic ejecuta handleClick, que actualiza el contador y registra un mensaje en la consola bajo la vista previa. Prueba onDoubleClick en lugar de onClick: ahora solo cuenta un doble clic.
Pasa la función, no la llames
La prop recibe una función, y React la llama después. Un error muy común es agregar paréntesis, lo que llama a la función de inmediato, durante el renderizado, y le entrega a React su valor de retorno.
La consola muestra "Hi, during render" antes de que toques nada: React ejecutó sayHi mientras renderizaba el primer botón, y como sayHi devuelve undefined, ese botón no tiene ningún manejador. Hacer clic en Wrong no hace nada. Hacer clic en Right registra "Hi, Ada", porque la función flecha solo se ejecuta al hacer clic.
La flecha también es la forma de pasar argumentos. onClick={() => removeItem(item.id)} crea una pequeña función para cada elemento, y esa función llama a la tuya con el ID correcto. Si un manejador no recibe argumentos, pásalo por su nombre: onClick={handleClick}.
Con un setter de estado el error es peor: onClick={setCount(count + 1)} cambia el estado durante el renderizado, lo que vuelve a renderizar, lo que vuelve a cambiar el estado, y React se detiene con "Too many re-renders".
El objeto de evento
React pasa a cada manejador un argumento, el objeto de evento. Tiene las mismas propiedades que el evento del navegador: e.target es el elemento donde ocurrió el evento, e.key es la tecla pulsada, e.preventDefault() cancela la acción por defecto del navegador. React envuelve el evento nativo en lo que llama un evento sintético, para que se comporte igual en todos los navegadores; el original está en e.nativeEvent si alguna vez lo necesitas.
Los dos que más usas son e.target.value en onChange y e.key en onKeyDown.
Escribe hooks y pulsa Enter: la etiqueta se agrega y el campo se vacía. La consola registra cada tecla, incluidas Shift, Backspace y Enter, con los nombres de e.key. Pulsa Escape a mitad de una palabra para descartarla.
El onChange de React se dispara en cada pulsación. En HTML puro, el evento change de un campo de texto solo se dispara cuando pierde el foco, así que esta es una diferencia deliberada: permite que el input y el estado avancen juntos letra por letra. Las casillas te dan e.target.checked en lugar de value. La página de formularios cubre todos los tipos de input.
Formularios y preventDefault
Cuando se envía un formulario, la acción por defecto del navegador es mandarlo y cargar una página nueva. En una app de React casi siempre quieres manejar los datos tú mismo, así que el manejador de envío empieza con e.preventDefault().
Pon onSubmit en el <form>, no onClick en el botón: así pulsar Enter en el campo también envía, y las comprobaciones propias del navegador (aquí required y type="email") se ejecutan primero. Borra la línea e.preventDefault() y vuelve a enviar: una página real se iría a una página nueva y perdería el mensaje de agradecimiento. La vista previa lo bloquea y muestra en su lugar lo que el formulario enviaría, email= sin valor, porque setEmail('') ya había vaciado el campo cuando se leyó el formulario.
React 19 también te permite pasar una función a <form action={fn}>, que recibe los datos del formulario y reinicia por ti los campos no controlados. La página de formularios muestra ambos estilos.
Propagación y stopPropagation
La mayoría de los eventos se propagan hacia arriba: después de ejecutarse en el elemento donde hiciste clic, se ejecutan en su padre, luego en el padre del padre, hasta arriba. Los manejadores de React siguen el mismo orden. Por eso un clic en un botón dentro de una tarjeta clicable también cuenta como un clic en la tarjeta.
Haz clic en Bubbles up y la consola registra el botón, luego el panel interior, luego la tarjeta exterior. Haz clic en Stops here y solo registra el botón: e.stopPropagation() detiene la subida. Hacer clic en el texto del panel interior registra el panel y la tarjeta.
Usa stopPropagation con moderación. Un caso legítimo habitual es un botón de borrar dentro de una fila de lista clicable, donde hacer clic en borrar no debe abrir también la fila. Si un padre necesita saber si el clic vino de un hijo, revisa e.target en lugar de detener el evento. Para ejecutar un manejador en el camino de bajada, antes de que los hijos vean el evento, React ofrece versiones de captura como onClickCapture.
preventDefault y stopPropagation son herramientas distintas. La primera cancela lo que haría el navegador (seguir un enlace, enviar un formulario, marcar una casilla). La segunda impide que otros manejadores se enteren del evento. Llamar a una no hace lo de la otra.
Otros eventos comunes
El mismo patrón cubre todos los eventos que admite React. Algunos que usarás a menudo:
onFocusyonBlurse disparan cuando un input gana y pierde el foco, útil para mostrar la validación después de que el usuario sale de un campo.onMouseEnteryonMouseLeavese disparan cuando el puntero entra en un elemento y sale de él. A diferencia de la mayoría de los eventos no se propagan, así que mover el puntero de un padre a su hijo no vuelve a disparar elonMouseEnterdel padre.onPointerDown,onPointerMoveyonPointerUpfuncionan igual con ratón, pantalla táctil y lápiz, lo que los convierte en la mejor opción para arrastrar.onScrollse dispara mientras un elemento se desplaza. En React no se propaga.
Cada manejador recibe un objeto de evento con las propiedades que tienen sentido para él: e.clientX para eventos de puntero, e.key para eventos de teclado, e.target para todos.
Pasar manejadores como props
Los componentes pueden aceptar manejadores de su padre como cualquier otra prop. Nómbralos onSomething según lo que pasó, y nombra handleSomething a la función que lo maneja. Esto imita los eventos integrados y deja claro qué props son callbacks.
Stepper no es dueño del número; comunica los clics y el padre decide qué significan. Cambia handleDecrement para que se detenga en 1 en lugar de 0 y el stepper lo sigue sin editarlo. Mantener el estado en el padre y pasar manejadores hacia abajo es el patrón descrito en elevar el estado.
Las props de manejadores personalizadas son solo nombres. onIncrement en tu propio componente no hace nada hasta que el componente lo pasa al onClick de un elemento real, y puedes darle los argumentos que quieras, por ejemplo onSelect(item.id).
Preguntas frecuentes
¿Cómo paso un parámetro a un manejador onClick?
Envuelve la llamada en una función flecha: onClick={() => deleteItem(item.id)}. La flecha es lo que React llama al hacer clic, y ella llama a tu función con el argumento.
¿Por qué mi onClick se ejecuta cuando carga la página?
Llamaste a la función en lugar de pasarla. onClick={handleClick()} ejecuta handleClick durante el renderizado y pasa su valor de retorno. Escribe onClick={handleClick} u onClick={() => handleClick(id)}.
¿Cuál es la diferencia entre onChange en React y en HTML?
En HTML el evento change de un input de texto se dispara cuando el input pierde el foco. El onChange de React se dispara en cada pulsación, como el evento nativo input, para que el estado pueda seguir el texto mientras se escribe.
¿Cómo evito que un formulario recargue la página en React?
Llama a e.preventDefault() al inicio del manejador onSubmit. Pon el manejador en el <form>, no en el botón de envío, para que pulsar Enter en un campo también envíe.
¿Qué es un evento sintético en React?
Es el objeto de evento que React pasa a tus manejadores. Envuelve el evento nativo del navegador con las mismas propiedades y métodos (target, key, preventDefault(), stopPropagation()) y se comporta igual en todos los navegadores. El original está disponible como e.nativeEvent.