노트

이벤트 버블링·캡처링과 위임

Event Bubbling and Capturing

프런트엔드#browser#js · 연결된 개념 5개

쉽게 말하면

이벤트 버블링은 사원 책상에서 일어난 일이 팀장, 부장으로 차례로 보고되는 거예요. 그래서 부장 한 명만 귀를 열어 두면 팀원 누가 클릭해도 알 수 있는데, 이게 이벤트 위임이에요.

비유가 깨지는 곳 보고가 아래에서 위로만 가는 건 아니에요. 먼저 루트에서 대상까지 내려가는 캡처링이 있고 그다음 버블링이 와요. focus처럼 버블링하지 않는 이벤트도 있고, stopPropagation과 preventDefault는 별개예요.

DOM 이벤트는 대상 요소에서만 끝나지 않고 트리를 따라 전파된다. 루트에서 대상까지 내려가는 캡처링(Capturing Phase), 대상에서 처리되는 타깃 단계(Target Phase), 대상에서 루트로 올라가는 버블링(Bubbling Phase) 순서다.

  • addEventListener는 기본으로 버블링 단계에서 실행된다. 세 번째 인자로 true나 { capture: true }를 주면 캡처링 단계에서 먼저 실행된다
  • event.stopPropagation()은 전파를 멈추고, event.preventDefault()는 링크 이동·폼 제출 같은 기본 동작만 막는다. 둘은 별개다
  • focus, blur, mouseenter처럼 버블링하지 않는 이벤트도 있다(대신 focusin·focusout은 버블링한다)
  • event.target은 실제로 이벤트가 일어난 요소, event.currentTarget은 지금 핸들러가 붙은 요소다
sequenceDiagram
  participant W as window
  participant D as document
  participant P as 부모
  participant T as 타깃 요소
  Note over W,T: 캡처링 단계 (루트에서 대상으로)
  W->>D: 전파
  D->>P: 전파
  P->>T: 전파
  Note over T: 타깃 단계
  Note over W,T: 버블링 단계 (대상에서 루트로)
  T->>P: 전파
  P->>D: 전파
  D->>W: 전파
parent.addEventListener('click', () => log('부모(캡처)'), true)
child.addEventListener('click', () => log('자식'))
parent.addEventListener('click', () => log('부모(버블)'))
// 자식 클릭: 부모(캡처) → 자식 → 부모(버블)

이벤트 위임(Event Delegation)

자식마다 핸들러를 붙이지 않고, 부모 하나에 붙여 버블링으로 올라온 이벤트를 target으로 구분하는 기법. 핸들러 수가 줄고, 나중에 추가된 자식도 따로 등록할 필요가 없다.

list.addEventListener('click', e => {
  const btn = e.target.closest('button[data-id]')
  if (btn) remove(btn.dataset.id)
})

React는 이벤트 위임을 기본으로 쓴다. 각 요소가 아니라 루트 컨테이너에 리스너를 달고, 자체 합성 이벤트(Synthetic Event)로 전파를 흉내 낸다. 그래서 포털 안의 이벤트도 DOM 위치가 아니라 React 트리를 따라 버블링한다. 이 구조는 한 곳에서 구독자에게 알리는 옵저버 패턴과도 닮았다.

참고: MDN — Event bubbling

연결된 개념

이 노트를 가리키는 문서

뜻이 가까운 노트

  • 이벤트 루프

    자바스크립트를 실행하는 하나의 스레드가 할 일을 큐에서 하나씩 꺼내 처리하는 반복 구조. JS 엔진 자체에는 타이머도 네트워크도 없고, 브라우저(또는 Node.js)가 이 루프를 돌리면서 콜백을 엔진에 넘겨준다.

  • useEffectEvent

    useEffectEvent는 Effect 안에서 부르되 의존성 배열(Dependency Array)에는 넣지 않는 이벤트 함수를 만드는 훅이다. 항상 최신 props·state를 읽지만, 그 값이 바뀐다고 Effect가 다시 실행되지는 않는다. React 19.2에서 정식이 됐다(2026 기준).

  • React Testing Library

    React Testing Library(RTL)는 컴포넌트를 jsdom 같은 테스트용 DOM(Document Object Model) 환경에 렌더하고, 사용자가 실제로 쓰는 방식으로 요소를 찾고 조작하게 해 주는 테스트 도구다. 내부 구현(state, 메서드)이 아니라 화면에 보이는 동작을 검증하라는 철학을 강하게 가진 라이브러리다.

  • HTMX

    HTML 속성만으로 서버에 요청을 보내고, 응답으로 받은 HTML 조각을 페이지 일부에 끼워 넣게 해 주는 작은 라이브러리. 클라이언트에서 JSON(JavaScript Object Notation)을 받아 상태와 화면을 그리는 SPA(Single Page Application)와 달리, 서버가 화면 조각을 만들어 보내는 방식(하이퍼미디어, Hypermedia)으로 돌아간다.

  • 동기·비동기와 블로킹·논블로킹

    동기·비동기는 결과를 언제 어떻게 받느냐, 블로킹·논블로킹은 기다리는 동안 호출한 스레드가 멈추느냐의 문제다.

보기 옵션