Responder a eventos
React te permite agregarmanejadores de eventosa tu JSX. Los manejadores de eventos son tus propias funciones que se activarán en respuesta a interacciones como hacer clic, pasar el cursor, enfocar entradas de formulario, y así sucesivamente.
Aprenderás
- Diferentes formas de escribir un manejador de eventos
- Cómo pasar la lógica de manejo de eventos desde un componente padre
- Cómo se propagan los eventos y cómo detenerlos
Agregar manejadores de eventos
Para agregar un manejador de eventos, primero definirás una función y luego lapasarás como propa la etiqueta JSX apropiada. Por ejemplo, aquí hay un botón que aún no hace nada:
Puedes hacer que muestre un mensaje cuando un usuario hace clic siguiendo estos tres pasos:
- Declara una función llamada
handleClickdentrode tu componenteButton. - Implementa la lógica dentro de esa función (usa
alertpara mostrar el mensaje). - Agrega
onClick={handleClick}al JSX del<button>.
Definiste la funciónhandleClicky luego lapasaste como prop a <button>.handleClickes unmanejador de eventos.Las funciones manejadoras de eventos:
- Generalmente se definendentrode tus componentes.
- Tienen nombres que comienzan con
handle, seguido del nombre del evento.
Por convención, es común nombrar a los manejadores de eventos comohandleseguido del nombre del evento. A menudo verásonClick={handleClick},onMouseEnter={handleMouseEnter}, y así sucesivamente.
Alternativamente, puedes definir un manejador de eventos en línea en el JSX:
O, más concisamente, usando una función flecha:
Todos estos estilos son equivalentes. Los manejadores de eventos en línea son convenientes para funciones cortas.
Precaución
Las funciones que se pasan a los manejadores de eventos deben pasarse, no llamarse. Por ejemplo:
| pasar una función (correcto) | llamar a una función (incorrecto) |
|---|---|
<button onClick={handleClick}> | <button onClick={handleClick()}> |
La diferencia es sutil. En el primer ejemplo, la funciónhandleClickse pasa como un manejador de eventosonClick. Esto le dice a React que la recuerde y solo llame a tu función cuando el usuario haga clic en el botón.
En el segundo ejemplo, los()al final dehandleClick()ejecutan la funcióninmediatamentedurante elrenderizado, sin ningún clic. Esto se debe a que el JavaScript dentro de lasllaves { y } del JSXse ejecuta de inmediato.
Cuando escribes código en línea, la misma precaución se presenta de una manera diferente:
| pasar una función (correcto) | llamar a una función (incorrecto) |
|---|---|
<button onClick={() => alert('...')}> | <button onClick={alert('...')}> |
Pasar código en línea como este no se activará al hacer clic; se activará cada vez que el componente se renderice:
Si quieres definir tu manejador de eventos en línea, envuélvelo en una función anónima así:
En lugar de ejecutar el código dentro con cada renderizado, esto crea una función para ser llamada más tarde.
En ambos casos, lo que quieres pasar es una función:
<button onClick={handleClick}>pasa la funciónhandleClick.<button onClick={() => alert('...')}>pasa la función() => alert('...').
Leer props en manejadores de eventos
Debido a que los manejadores de eventos se declaran dentro de un componente, tienen acceso a las props del componente. Aquí hay un botón que, al hacer clic, muestra una alerta con su propmessage:
Esto permite que estos dos botones muestren mensajes diferentes. Intenta cambiar los mensajes que se les pasan.
Pasar manejadores de eventos como props
A menudo querrás que el componente padre especifique el manejador de eventos de un componente hijo. Considera los botones: dependiendo de dónde uses un componenteButton, es posible que quieras ejecutar una función diferente—quizás una reproduzca una película y otra suba una imagen.
Para hacer esto, pasa una prop que el componente recibe de su padre como el manejador de eventos, así:
Aquí, el componenteToolbarrenderiza unPlayButtony unUploadButton:
PlayButtonpasahandlePlayClickcomo la proponClickalButtoninterno.UploadButtonpasa() => alert('Uploading!')como la proponClickalButtoninterno.
Finalmente, tu componenteButtonacepta una prop llamadaonClick. Pasa esa prop directamente al<button>integrado del navegador cononClick={onClick}. Esto le dice a React que llame a la función pasada al hacer clic.
Si usas unsistema de diseño, es común que componentes como botones contengan estilos pero no especifiquen el comportamiento. En su lugar, componentes comoPlayButton y UploadButtonpasarán los manejadores de eventos hacia abajo.
Nombrar props de manejadores de eventos
Los componentes integrados como<button> y <div>solo admitennombres de eventos del navegadorcomoonClick. Sin embargo, cuando construyes tus propios componentes, puedes nombrar las props de sus manejadores de eventos de la manera que prefieras.
Por convención, las props de los manejadores de eventos deben comenzar conon, seguido de una letra mayúscula.
Por ejemplo, la proponClickdel componenteButtonpodría haberse llamadoonSmash:
En este ejemplo,<button onClick={onSmash}>muestra que el<button>del navegador (en minúsculas) aún necesita una prop llamadaonClick, ¡pero el nombre de la prop recibida por tu componente personalizadoButtondepende de ti!
Cuando tu componente admite múltiples interacciones, podrías nombrar las props de los manejadores de eventos para conceptos específicos de la aplicación. Por ejemplo, este componenteToolbarrecibe los manejadores de eventosonPlayMovie y onUploadImage:
Observa cómo el componenteAppno necesita saberquéToolbarhará cononPlayMovie o onUploadImage. Ese es un detalle de implementación deToolbar. Aquí,Toolbarlos pasa como manejadoresonClick a sus Buttons, pero más tarde también podría activarlos con un atajo de teclado. Nombrar las props según interacciones específicas de la aplicación comoonPlayMoviete da la flexibilidad de cambiar cómo se usan más adelante.
Nota
Asegúrate de usar las etiquetas HTML apropiadas para tus manejadores de eventos. Por ejemplo, para manejar clics, usa<button onClick={handleClick}>en lugar de<div onClick={handleClick}>. Usar un<button>real del navegador habilita comportamientos integrados como la navegación por teclado. Si no te gusta el estilo por defecto del navegador para un botón y quieres que se vea más como un enlace u otro elemento de la interfaz, puedes lograrlo con CSS.Aprende más sobre cómo escribir marcado accesible.
Propagación de eventos
Los manejadores de eventos también capturarán eventos de cualquier hijo que pueda tener tu componente. Decimos que un evento "burbujea" o "se propaga" hacia arriba en el árbol: comienza donde ocurrió el evento y luego sube por el árbol.
Este<div>contiene dos botones. Tanto el<div>comocada botón tienen sus propios manejadoresonClick. ¿Qué manejadores crees que se activarán cuando hagas clic en un botón?
Si haces clic en cualquiera de los botones, suonClickse ejecutará primero, seguido del<div>padreonClick. Así que aparecerán dos mensajes. Si haces clic en la barra de herramientas misma, solo se ejecutará el<div>padreonClick.
Pitfall
Todos los eventos se propagan en React exceptoonScroll, que solo funciona en la etiqueta JSX a la que lo adjuntas.
Detener la propagación
Los manejadores de eventos reciben unobjeto de eventocomo su único argumento. Por convención, normalmente se llamae, que significa "evento". Puedes usar este objeto para leer información sobre el evento.
Ese objeto de evento también te permite detener la propagación. Si quieres evitar que un evento llegue a los componentes padres, necesitas llamar ae.stopPropagation()como lo hace este componenteButton:
Cuando haces clic en un botón:
- React llama al manejador
onClickpasado al<button>. - Ese manejador, definido en
Button, hace lo siguiente:- Llama a
e.stopPropagation(), evitando que el evento se propague más. - Llama a la función
onClick, que es una prop pasada desde el componenteToolbar.
- Llama a
- Esa función, definida en el componente
Toolbar, muestra la alerta propia del botón. - Como se detuvo la propagación, el manejador
<div>delonClickpadrenose ejecuta.
Como resultado dee.stopPropagation(), hacer clic en los botones ahora solo muestra una alerta (del<button>) en lugar de las dos (del<button> y del <div>padre de la barra de herramientas). Hacer clic en un botón no es lo mismo que hacer clic en la barra de herramientas que lo rodea, por lo que detener la propagación tiene sentido para esta interfaz de usuario.
Pasar manejadores como alternativa a la propagación
Observa cómo este manejador de clic ejecuta una línea de códigoy luegollama a la proponClickpasada por el padre:
También podrías agregar más código a este manejador antes de llamar al manejador de eventosonClickdel padre. Este patrón proporciona unaalternativaa la propagación. Permite que el componente hijo maneje el evento, mientras que también permite que el componente padre especifique algún comportamiento adicional. A diferencia de la propagación, no es automático. Pero la ventaja de este patrón es que puedes seguir claramente toda la cadena de código que se ejecuta como resultado de algún evento.
Si dependes de la propagación y es difícil rastrear qué manejadores se ejecutan y por qué, prueba este enfoque en su lugar.
Prevenir el comportamiento predeterminado
Algunos eventos del navegador tienen un comportamiento predeterminado asociado. Por ejemplo, un evento de envío de<form>, que ocurre cuando se hace clic en un botón dentro de él, recargará toda la página de forma predeterminada:
Puedes llamar ae.preventDefault()en el objeto del evento para evitar que esto suceda:
No confundase.stopPropagation() y e.preventDefault(). Ambos son útiles, pero no están relacionados:
- e.stopPropagation()evita que se activen los controladores de eventos adjuntos a las etiquetas superiores.
- e.preventDefault()previene el comportamiento predeterminado del navegador para los pocos eventos que lo tienen.
¿Pueden los controladores de eventos tener efectos secundarios?
¡Absolutamente! Los controladores de eventos son el mejor lugar para los efectos secundarios.
A diferencia de las funciones de renderizado, los controladores de eventos no necesitan serpuros, por lo que es un gran lugar paracambiaralgo—por ejemplo, cambiar el valor de una entrada en respuesta a la escritura, o cambiar una lista en respuesta a la pulsación de un botón. Sin embargo, para cambiar alguna información, primero necesitas alguna forma de almacenarla. En React, esto se hace utilizandoel estado, la memoria de un componente.Aprenderás todo sobre ello en la siguiente página.
Recapitulación
- Puedes manejar eventos pasando una función como prop a un elemento como
<button>. - Los controladores de eventos deben pasarse,¡no llamarse!
onClick={handleClick}, noonClick={handleClick()}. - Puedes definir una función controladora de eventos por separado o en línea.
- Los controladores de eventos se definen dentro de un componente, por lo que pueden acceder a las props.
- Puedes declarar un controlador de eventos en un padre y pasarlo como prop a un hijo.
- Puedes definir tus propias props de controlador de eventos con nombres específicos de la aplicación.
- Los eventos se propagan hacia arriba. Llama a
e.stopPropagation()en el primer argumento para prevenirlo. - Los eventos pueden tener un comportamiento predeterminado no deseado del navegador. Llama a
e.preventDefault()para prevenirlo. - Llamar explícitamente a una prop de controlador de eventos desde un controlador hijo es una buena alternativa a la propagación.
Prueba algunos desafíos
Challenge 1 of 2:Corrige un controlador de eventos #
Al hacer clic en este botón se supone que debe cambiar el fondo de la página entre blanco y negro. Sin embargo, no sucede nada cuando haces clic. Corrige el problema. (No te preocupes por la lógica dentro de handleClick—esa parte está bien.)
