이벤트 위임: 리스너는 부모에 하나만
그로스앤디 · 2026-10-06
오늘 배운 것 한 줄
이벤트는 클릭한 요소에서 끝나지 않고 부모 쪽으로 올라가요. 그래서 리스너는 자식마다 달지 않고 부모에 하나만 둬도 된다.
왜 중요한가
얼마 전에 만든 todo 앱은 할 일 하나를 그릴 때마다 체크박스, 수정, 삭제 버튼에 리스너를 따로 붙였어요. 할 일이 20개면 리스너가 60개예요. 그런데 이벤트에는 버블링이 있어요. 버튼에서 난 클릭이 li를 거쳐 ul까지 올라오니까, ul이 대신 들으면 되는 거죠.
좋은 점이 하나 더 있어요. 목록을 다시 그려도 리스너를 다시 달 필요가 없어요. 부모는 그대로 남아 있으니까요.
내 예시
// 전: 항목을 그릴 때마다 버튼마다 리스너
deleteButton.addEventListener('click', () => removeTodo(todo.id));
// 후: 목록에 리스너 하나
list.addEventListener('click', (event) => {
const button = event.target.closest('button[data-action]');
if (!button || !list.contains(button)) return; // 버튼 밖 클릭은 무시
const id = button.closest('li').dataset.id;
if (button.dataset.action === 'delete') removeTodo(id);
if (button.dataset.action === 'edit') startEdit(id);
});
event.target은 실제로 누른 요소예요. 버튼 안의 글자를 누르면 글자가 잡히거든요. 그래서 closest로 가장 가까운 버튼을 찾아 올라가요.
다음에 해 볼 것
todo 앱에 실제로 적용해 볼 거예요. 하나 걸리는 게 있어요. focus와 blur는 버블링하지 않아요. 수정 입력창의 포커스를 부모에서 들으려면 focusin과 focusout을 써야 해요.
이벤트 전파 3단계 (캡처링·타깃·버블링) · 반복 UI 템플릿 렌더링