Eventos
Ya construiste un botón. Ahora necesita hacer algo cuando alguien lo haga clic, guardar un formulario, abrir un menú, eliminar un elemento. React maneja esto de la misma forma que maneja todo lo demás: a través de props. En lugar de llamar a addEventListener como hiciste en el capítulo de eventos en JavaScript, pasas una función directamente a un prop en el elemento que quieres escuchar. La idea es la misma: una función que se ejecuta cuando algo sucede, pero la forma en que lo conectas es un patrón de React único.
Adjuntar un manejador
function SaveButton() {
function handleClick() {
console.log('clicked')
}
return <button onClick={handleClick}>Guardar</button>
}Los props de eventos tienen nombres en camelCase, coincidiendo con el evento que escuchan: onClick para clics, onChange para cambios de valor en un campo, onSubmit para el envío de un formulario. Escribes el prop en el elemento y le das una función para ejecutar.
handleClick se define dentro del componente, y luego se pasa a onClick. React la ejecuta cada vez que se hace clic en el botón. Estás pasando la función por nombre, handleClick. Ejecutarla, handleClick(), la correría inmediatamente, durante el renderizado. Lo que haces es entregarle a React la función para ejecutar después, no ejecutarla tú ahora mismo.
Cuando necesitas detalles de qué sucedió, React pasa a tu manejador un objeto event con las mismas propiedades familiares, target, preventDefault(), y demás, que esperarías de addEventListener. Nombra un parámetro para capturarlo, convencionalmente event:
function SearchBox() {
function handleChange(event) {
console.log(event.target.value)
}
return <input onChange={handleChange} />
}event.target es el elemento en el que se disparó el evento, y event.target.value es el texto actual en el campo. Solo necesitas acceder al objeto event cuando un manejador realmente necesita esa información. El onClick de un botón frecuentemente no.
El error más común
Porque el manejador es una función que pasas a un prop, este es un error que atrapa a casi todos en algún momento:
// Incorrecto: ejecuta handleClick inmediatamente, mientras el componente se renderiza
<button onClick={handleClick()}>Guardar</button>
// Correcto: pasa la función en sí, React la ejecuta después, al hacer clic
<button onClick={handleClick}>Guardar</button>Los paréntesis son toda la diferencia. handleClick() ejecuta la función en ese instante, durante el renderizado, y lo que retorna (usualmente undefined) es lo que termina en onClick. handleClick le entrega a React la función en sí, para que la llame cuando el clic realmente suceda. Si un manejador parece ejecutarse por su cuenta en el momento en que la página carga, casi siempre es por esto.
Pasar manejadores hacia abajo como props
Un manejador no tiene que vivir en el mismo componente que el elemento al que está adjunto. Puedes definirlo en un padre y pasarlo hacia abajo a un hijo como un prop, de la misma forma que pasarías cualquier otro valor:
function SaveButton({ onSave }) {
return <button onClick={onSave}>Guardar</button>
}
function Form() {
function handleSave() {
console.log('guardado')
}
return <SaveButton onSave={handleSave} />
}Form es dueño de handleSave y lo pasa a SaveButton bajo el nombre de prop onSave. SaveButton no sabe ni le importa qué hace la función, solo la conecta a onClick. Así es como un clic en un componente pequeño y reutilizable termina activando lógica que vive más arriba en tu app, más cerca del state o los datos que esa lógica necesita.
Prevenir el comportamiento por defecto
Algunos eventos vienen con comportamiento del navegador adjunto, y enviar un formulario es el que encontrarás primero. Por defecto, enviar un formulario recarga la página, lo que descarta cualquier cosa que tu componente estuviera haciendo. Llama a event.preventDefault() dentro del manejador para evitar eso:
function SignupForm() {
function handleSubmit(event) {
event.preventDefault()
console.log('formulario enviado')
}
return (
<form onSubmit={handleSubmit}>
<input type="email" />
<button type="submit">Registrarse</button>
</form>
)
}Adjunta onSubmit al <form> en sí, no onClick al botón. De esa forma, presionar Enter dentro del campo también envía el formulario, no solo hacer clic en el botón.
onClick y onChange, y les das una función para ejecutar, no el resultado de ejecutarla. Escribe onClick={handleClick}, nunca onClick={handleClick()}. Cuando un manejador necesita detalles de qué sucedió, captúralos con un parámetro nombrado event.
Siguiente: Renderizado condicional, donde lo que un componente retorna comienza a depender de los datos que tiene.

