학습자료 : 1분 코딩 - 자바스크립트 이벤트 위임 핵심 정리
- 이번 프로젝트에서는 데이터 배열을 가공해서 insertAdjacenthtml을 통해 다양한 노드로 생성하여 렌더링하고 반복문을 사용하여 각 요소마다 이벤트를 걸어주는 패턴을 상당히 많이 사용했다.
- 그 과정에서 받은 피드백 중 하나가 모든 요소에 반복물을 이용해 이벤트를 걸어주는 것은 비효율적이고, 감시해야 하는 대상이 늘어나기 때문에 성능면에서도 좋지 않다는 것이였다.
- 반복문 대신 이벤트 위임에 대해 알아보라는 말을 들었고 학습한 내용을 바탕으로 정리해봤다.
수량 조절 버튼이 하나만 사용되는 상품 상세 페이지와는 다르게 장바구니 페이지에서는 상품마다 수량 조절 버튼이 생성된다. 그리고 감시하는 대상과 계속해서 늘어나게 된다. (이미지 참고)
+,-버튼 각각 이벤트를 달았지만 같은 콜백 함수를 사용하기 때문에 +버튼의 클릭 이벤트에서도 -버튼의 이벤트인지 판단하는 코드가 들어가는 비효율이 발생한다.
그리고 DOM에 변경사항이 생기면 하위 요소마다 수정해야 한다는 유지보수 측면의 비효율도 발생할 것 같다.
const quantityControlBox = (doc) => {
const $upButton = doc.querySelector('#quantityUp');
const $downButton = doc.querySelector('#quantityDown');
const $quantityInput = doc.querySelector('#quantityInput');
$upButton.addEventListener('click', controlQuantity);
$downButton.addEventListener('click', controlQuantity);
// 하나의 콜백 함수로 구현했기 때문에, +를 눌러도 -인지 판단하는 코드가 들어간다.
function controlQuantity(e) {
if (e.target.id == 'quantityUp') {
$quantityInput.value = Number($quantityInput.value) + 1;
} else if (e.target.id == 'quantityDown' && $quantityInput.value != 1) {
$quantityInput.value = Number($quantityInput.value) - 1;
}
위와 같이 요소마다 핸들러를 두지 않고, 여러 요소의 상위 요소에 하나의 핸들러를 두어 하위 요소의 이벤트를 관리하는 것을 이벤트 위임이라고 한다.
이벤트 위임의 종류에는 이벤트 버블링, 캡처링이 있다.
모던자바스크립트 예시
<form onclick="alert('form')">FORM
<div onclick="alert('div')">DIV
<p onclick="alert('p')">P</p>
</div>
</form>
간단한 예시로 테이블 요소가 있고 그 속에 수십만개의 data cell이 있고, data cell에 checkbox 요소를 넣고 checkbox의 이벤트를 감시해야 한다고 가정한다.
이를 위해 수십만개의 이벤트를 넣고 체크박스를 하나하나 관리하는 건 당연히 비효율적이다. 여기서 table 요소에 하나의 핸들러를 두어 모든 셀의 이벤트를 감시하는 이벤트 위임을 사용하여 위와 같은 상황을 방지할 수 있다.
<table>
<tr>
</tr>
<tr>
<td class="n">...</td>
<td class="n">...</td>
...
</tr>
<tr>
...
</tr>
...
</table>
이벤트 위임 사용 전
const td = document.querySelectorAll('td')
td.forEach(e=>e.addEventListener(....)
이벤트 위임 사용 후
const table = document.querySelector('table')
table.addEventListener(...)
const quantityControlBox = (doc) => {
const $quantityBox = document.getElementById('updownBtnBox'); // 수량조절박스
const $quantityInput = doc.querySelector('#quantityInput');
$upButton.addEventListener('click', controlQuantity);
$downButton.addEventListener('click', controlQuantity);
function controlQuantity(e) {
if (e.target.id == 'quantityUp') {
$quantityInput.value = Number($quantityInput.value) + 1;
} else if (e.target.id == 'quantityDown' && $quantityInput.value != 1) {
$quantityInput.value = Number($quantityInput.value) - 1;
}