여러 개의 하위 DOM 요소에 각각 이벤트 핸들러를 등록하는 대신 하나의 상위 DOM 요소에 이벤트 핸들러를 등록하는 방법
먼저 이벤트 위임 없이 DOM 요소 각각에 이벤트 핸들러를 등록하는 경우를 보자. <ul>
의 하위 요소인 여러 개의 <li>
요소에 각각 클릭 이벤트에 따른 이벤트 핸들러를 등록한다.
index.html
<nav>
<ul id="fruits">
<li id="apple" class="active">Apple</li>
<li id="banana">Banana</li>
<li id="peach">Peach</li>
</ul>
<div>선택된 과일 : <em class="msg">apple</em></div>
</nav>
style.css
#fruits {
display: flex;
list-style-type: none;
padding: 0;
}
#fruits li {
width: 100px;
cursor: pointer;
}
#fruits .active {
color: red;
text-decoration: underline;
}
index.js
import './style.css';
const fruits = document.getElementById('fruits');
const msg = document.querySelector('.msg');
function activate({ target }) {
if (!target.matches('#fruits > li')) return;
[...fruits.children].forEach((fruit) => {
fruit.classList.toggle('active', fruit === target);
msg.textContent = target.id;
});
}
// 모든 이벤트 타깃에 이벤트 핸들러 등록
document.getElementById('apple').onclick = activate;
document.getElementById('banana').onclick = activate;
document.getElementById('peach').onclick = activate;
위의 예시로는 3개의 <li>
요소가 전부이지만 이벤트 핸들러를 등록해야 하는 요소가 수 십, 수 백개인 경우에는? 해당 DOM 요소마다 이벤트 핸들러를 등록하게 되면 성능 저하를 유발하게 될 것이고 유지 보수 차원에서도 적절하지 않다.
이 때, 이벤트 전파
를 이용해 하나의 상위 DOM 요소에만 이벤트 핸들러를 등록함으로써 이벤트를 위임
하면, 하위 DOM 요소에 일일이 이벤트 핸들러를 등록하지 않아도 하위 요소들의 이벤트를 캐치할 수 있다.
index.js
import './style.css';
const fruits = document.getElementById('fruits');
const msg = document.querySelector('.msg');
function activate({ target }) {
if (!target.matches('#fruits > li')) return;
[...fruits.children].forEach((fruit) => {
fruit.classList.toggle('active', fruit === target);
msg.textContent = target.id;
});
}
// 상위 요소(ul#fruits)에 이벤트 위임
document.getElementById('fruits').onclick = activate;
<ul>
요소에 이벤트를 위임한 위의 코드는 <li>
요소에 일일이 이벤트 핸들러를 등록했을 때와 똑같은 기능을 수행해낸다.
리액트에서는 이벤트 위임
을 신경써본 적도, 이와 관련해 들어본 적도 없어서 궁금해져서 찾아봤다.
리액트는 자체적으로 모든 이벤트를 이벤트 위임하여 처리하고 있다고 한다. 개발자가 리액트 코드 상에서 이벤트 핸들러를 특정 요소에 등록을 했을 때 vanila JS에서처럼 이벤트 핸들러가 실제 해당 DOM 요소에 붙여지는 것이 아니라, document level로 이벤트를 위임하여 처리된다는 것이다. 편리한 리액트...!