hand Inicio
hand JSBloqs
hand GutenBloqs

Event Bubbling y el descontrol en JavaScript

El event bubbling y event capturing se refiere a cuando un evento se propaga hacia sus elementos padre, o al revés y hacia sus elementos hijo

Eventos

Los eventos son la manera que tenemos de monitorizar el comportamiento de nuestros usuarios

Por ejemplo, detectar cuando se hace click en un botón

Y para implementar este control sobre los eventos, utilizamos los listeners

Por ejemplo

js
el.addEventListener(event, () => {})

Donde event será algo tipo click

js
const el = document.getElementById('mi_boton')
el.addEventListener('click', () => {
console.log('elemento clicado!')
})

Bubbling y Capturing

Entendido esto, el bubbling y el capturing ocurren cuando tenemos listeners dentro de listeners

html
<div id="mi_div">
<button id="mi_boton_1">
Boton 1
<button id="mi_boton_2">Boton 2</button>
</button>
</div>
js
document.getElementById('mi_boton_1').addEventListener('click', () => console.log('boton 1 clicado!'))
document.getElementById('mi_boton_2').addEventListener('click', () => console.log('boton 2 clicado!'))
document.getElementById('mi_div').addEventListener('click', () => console.log('div clicado!'))

En este ejemplo, cuando clicamos el botón 1 o el botón 2 tenemos dos mensajes, el del button y el del div

Y por qué no tenemos bubbling dentro de los botones? Porque en html no puedes meter un botón dentro de otro botón, por lo que el bubbling ni está ni se le espera

Y si esto es el bubbling, el capturing es a la inversa

html
<div id="mi_div">
<button id="mi_boton_1">
Boton 1
<button id="mi_boton_2">Boton 2</button>
</button>
</div>
js
document.getElementById('mi_boton_1').addEventListener('click', () => console.log('boton1 clicado!'), { capture: true })
document.getElementById('mi_boton_2').addEventListener('click', () => console.log('boton2 clicado!'), { capture: true })
document.getElementById('mi_div').addEventListener('click', () => console.log('div clicado!'), { capture: true })

Y lo que hace es invertir el orden de los eventos (y en la práctica el de los console.log)

  • Antes, teníamos primero el click del botón, y luego el del div

  • Ahora, tenemos primero el click del div, y luego el del button

Cómo los paro? (React)

Y para pararlo?

Esto es algo que normalmente querremos hacer para evitar eventos descontrolados

Es tan sencillo como añadir un stopPropagation()

Pero mejor lo vemos en React

Aquí, en lugar de acceder al DOM con el addEventListener, utilizaremos la manera React a través del Virtual DOM

jsx
import React, { useRef } from 'react'

export const App = () => {
const divRef = useRef()
const buttonRef = useRef()

return (
<div ref={divRef} onClick={() => console.log('yo también!')}>
<h1>Hola</h1>
<button ref={buttonRef} onClick={() => console.log('clicando!')}>
clica!
</button>
</div>
)
}

export default App

Si queremos la versión capturing en lugar de la bubbling, en lugar de utilizar onClick utilizaremos onClickCapture

Y si queremos evitarlo?

Añadimos el stopPropagation(), un método del evento que recibimos por defecto en la función onClick

jsx
import React, { useRef } from 'react'

const log = (e, msg) => {
e.stopPropagation()
console.log(msg)
}

export const App = () => {
const div = useRef()
const button = useRef()

return (
<div ref={div} onClick={e => log(e, 'yo también!')}>
<h1>Hola</h1>
<button ref={button} onClick={e => log(e, 'clicando!')}>
clica!
</button>
</div>
)
}

export default App

Listos!

draw of me

Hola, tienes en mente desarrollar una web?

Si quieres, te ayudo

11ty para webs ultra-rápidaseleventy js
Gatsby para webs complejasgatsby js
WordPress para webs para el usuario finalwordpress

Escríbeme

Lista de correo: escribo algo de tanto en cuanto