Hola a todos Este artículo trata sobre la delegación de eventos en JavaScript y su implementación en react.js.

¿De qué se trata realmente? ¿Por qué y por qué?
Para comenzar, analicemos brevemente:
- ¿Qué es un evento?
- cómo ocurre la distribución;
- Procesando DOM Nivel 2 con un ejemplo en JavaScript;
Y finalmente: por qué no te olvides de la delegación en React.
El evento
JavaScript y HTML interactúan entre sí a través de eventos. Cada evento sirve para decirle a JavaScript que algo ha sucedido en el documento o en la ventana del navegador. Para capturar estos eventos, necesitamos oyentes (oyentes), tales controladores que se activan en caso de un evento.
Propagación de eventos
Orden. Resolviendo el problema: ¿cómo entender a qué parte de la página pertenece el evento? Se implementaron dos métodos: en Internet Explorer, "burbujeo de eventos" y en Netscape Communicator, "enganche de eventos".
Evento burbujeante
En este caso, el evento se desencadena en el nodo más profundo del árbol de documentos, después de lo cual sube a través de la jerarquía hasta la ventana misma.
<!DOCTYPE html> <html> <head> <title>Some title</title> </head> <body> <div id="myDiv">Click Me</div> </body> </html>
En este caso habrá el siguiente orden:
- elemento div
- elemento del cuerpo
- elemento html
- documento
- ventana
Ahora la navegación es compatible con todos los navegadores modernos, aunque con diferentes implementaciones.
En el caso de la intercepción de eventos, lo contrario es cierto:
- ventana
- documento
- elemento html
- elemento del cuerpo
- elemento div
Se pensó que el evento podría procesarse antes de que alcanzara el elemento objetivo (como se decidió en Netscape, más tarde recogido por todos los navegadores modernos).
Como resultado, tenemos la siguiente estructura para distribuir eventos DOM:
- ventana
- documento
- elemento html
- elemento del cuerpo // termina la fase de intercepción
- elemento div // fase objetivo
- elemento del cuerpo // comienza la fase de ascenso
- elemento html
- documento
- ventana
Este esquema se divide en tres fases: la fase de intercepción: el evento puede ser interceptado antes de que llegue al elemento, la fase objetivo (procesamiento por el elemento objetivo y la fase de ascenso) para realizar cualquier acción final en respuesta al evento.
Entonces, pasamos al procesamiento de eventos
Veamos un ejemplo típico de manejo de eventos en JavaScript.
const btn = document.getElementById('myDiv') btn.addEventListener("click", handler)
Todo no sería nada, pero aquí recordamos nuestro amado IE que se suscribe a eventos usando attachEvent, y para eliminar detachEvent. Y puedes suscribirte al evento varias veces. Y no olvide que al firmar una función anónima, no tenemos la oportunidad de cancelar su suscripción.
Pero no somos codificadores externos. Hagamos todo de acuerdo con el canon:
var EventUtil = { addHandler: function (elem, type, handler) { if (elem.addEventListener) { elem.addEventListener(type, handler, false) } else if (elem.attachEvent) { elem.attachEvent("on" + type, handler) } else { elem["on" = type] = hendler } }, removeHandler: function (elem, type, handler) { if (elem.removeEventListener) { elem.removeEventListener(type, handler, false) } else if (elem.detachEvent) { elem.detachEvent("on" + type, handler) } else { elem["on" = type] = null } } }
Muy bien, pero ¿qué pasa con el objeto de evento? Después de todo, en IE no hay .target .srcElement, preventDefault? sin returnValue = falso. Pero no hay nada que agregar un par de métodos:
var EventUtil = { addHandler: function (elem, type, handler) { if (elem.addEventListener) { elem.addEventListener(type, handler, false) } else if (elem.attachEvent) { elem.attachEvent("on" + type, handler) } else { elem["on" = type] = hendler } }, getEvent: function (event) { return event ? event : window.event }, getTarget: function (event) { return event.target || event.srcElement }, preventDefault: function (event) { if (event.preventDefault) { event.preventDefault() } else { event.returnValue = false } }, removeHandler: function (elem, type, handler) { if (elem.removeEventListener) { elem.removeEventListener(type, handler, false) } else if (elem.detachEvent) { elem.detachEvent("on" + type, handler) } else { elem["on" = type] = null } }, stopPropagation: function (event) { if (event.stopPropagation) { event.stopPropagation() } else { event.cancelBubble = true } } }
Etc. etc. Y estos son todos bailes.
Bien, estamos bien hechos, resolvimos todos los problemas, todo está bien. Es cierto que el código salió bastante engorroso. Ahora imagine que necesitamos muchas suscripciones a muchos elementos. Wow, se necesitan bastantes líneas de código. Un ejemplo:
<ul> <li id="id1">go somewhere</li> <li id="id2">do something</li> <li id="some-next-id">next</li> </ul> var item1 = document.getElementById('id1') var item2 = document.getElementById('id2') var itemNext = document.getElementById('some-next-id') EventUtil.addHandler(item1, "click", someHandle) EventUtil.addHandler(item2, "click", someHandle2) EventUtil.addHandler(itemNext, "click", someHandle3)
Y así, para cada elemento, y no debemos olvidar eliminar, trabajar con target y similares
Y aquí la delegación del evento viene en nuestra ayuda.
Todo lo que necesitamos hacer es conectar un solo controlador al punto más alto en el árbol DOM:
<ul id="main-id">
Como resultado, solo tenemos un controlador en la memoria, y la propiedad id se puede usar para la acción deseada. Menos consumo de memoria mejora el rendimiento general de la página. El registro de un controlador de eventos requiere menos tiempo y menos llamadas al DOM. La excepción es quizás mouseover y mouseout, con ellos todo es un poco más complicado.
¿Y qué hay de Reaccionar?
Todo lo relacionado con la compatibilidad entre navegadores para nosotros ya ha sido hecho por chicos de Facebook. Todos nuestros controladores de eventos reciben una instancia de SyntheticEvent . Lo que nos encarga de reutilizar eventos del grupo, eliminando todas las propiedades después de llamar al controlador.
Bueno
Sin embargo, un controlador adicional es un controlador adicional. Me encontré varias veces, y me arrepiento, escribí este tipo de código:
class Example extends React.Component { handleClick () { console.log('click') } render () { return ( <div> {new Array(20).fill().map((_, index) => <div key={index} // elem.id id={index} // elem.id onClick={() => console.log('click')} /> )} </div> ) } }
El ejemplo muestra el caso cuando hay algún tipo de hoja con n-número de elementos, y por lo tanto con n-número de registros de manejadores.
Vamos a correr, ve a la página y comprueba cuántos manejadores están en acción en este momento. Para esto, encontré un buen script:
Array.from(document.querySelectorAll('*')) .reduce(function(pre, dom){ var clks = getEventListeners(dom).click; pre += clks ? clks.length || 0 : 0; return pre }, 0)
Funciona en Chrome Dev-Tool.
Y ahora delegamos todo esto al div y cheers padre, solo optimizamos nuestra aplicación n = array.length times. Código de ejemplo a continuación:
class Example extends React.Component { constructor () { super() this.state = { useElem: 0 } } handleClick (elem) { var id = elem.target.id this.setState({ useElem: id }) } render () { return ( <div onClick={this.handleClick}> {new Array(20).fill().map((_, index) => <div key={index} // elem.id id={index} // elem.id useElem={index === this.state.useElem} /> )} </div> ) } }
La delegación es una buena herramienta para procesar una gran cantidad de suscripciones, y en el caso de renderizado dinámico y redibujos frecuentes, es simplemente insustituible. Lástima los recursos del usuario, no son ilimitados.
Este artículo está basado en un libro de JavaScript para desarrolladores web profesionales, escrito por Nicholas Zakas.
Muchas gracias por su atención Si tiene algo que compartir o encuentra algún tipo de falla, tal vez un error o simplemente tiene una pregunta, escriba los comentarios. Estaré encantado de cualquier comentario!