Notice
Recent Posts
Recent Comments
Link
«   2025/08   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31
Tags
more
Archives
Today
Total
관리 메뉴

ssjeu_

[React] React에서 이벤트 처리 (1) - 버블링, 캡쳐링 본문

React ·JS

[React] React에서 이벤트 처리 (1) - 버블링, 캡쳐링

ssjeu 2022. 9. 11. 18:23
  1. 버블링, 캡쳐링
  2. 이벤트 위임
  3. 리액트에서 이벤트 처리

1. 이벤트 관리 - 버블링, 캡쳐링

이벤트란?

 

📍 이벤트: 클릭이나 스크롤을 내리는 등 사용자와 웹페이지가 상호 작용을 하며 브라우저가 감지하는 것

이벤트는 무언가 일어났다는 신호로 모든 DOM 노드는 이런 신호를 만들어 낸다. 참고로, 이벤트는 DOM에만 한정되진 않는다.

DOM Event 예시

  • 마우스 이벤트: click(마우스 왼쪽 클릭), contextmenu(마우스 오른쪽 클릭), mouseover, mouseout, mousedown, mouseup, mousemove
  • 키보드 이벤트: keydown(키보드 누를 때), keyup(키보드 뗄 때)
  • 폼요소 이벤트: submit, focus
  • CSS 이벤트: transitionend(애니메이션이 종료되었을 때)

 

📍 이벤트 리스너, 이벤트 핸들러: 어떤 이벤트 발생 시 처리하는 함수

이벤트에 반응하려면 이벤트가 발생했을 때 실행되는 함수인 핸들러(handler) 를 할당해야 한다.

핸들러는 사용자의 행동에 어떻게 반응할지를 자바스크립트 코드로 표현

📖 이벤트 핸들러 할당 방식

 

이벤트 버블링 (Event Bubbling)

 

📍 이벤트 버블링 원리: 이벤트 발생 시 요소에 할당된 핸들러 동작 후에 최상단의 조상요소 만날 때까지 부모요소 핸들러를 동작

한 요소에 이벤트가 발생하면, 이 요소에 할당된 핸들러가 동작하고, 이어서 부모 요소의 핸들러가 동작한다. 가장 최상단의 조상 요소를 만날 때까지 이 과정이 반복되면서 요소 각각에 할당된 핸들러가 동작한다.

<div onclick="alert('div에 할당한 핸들러!')">
  <em><code>EM</code>을 클릭했는데도 <code>DIV</code>에 할당한 핸들러가 동작합니다.</em>
</div>

핸들러는 <div>에 할당되어 있지만, <em> 이나 <code>같은 중첩 태그를 클릭해도 동작

->  이벤트가 제일 깊은 곳에 있는 요소에서 시작해 부모 요소를 거슬러 올라가며 발생하는 모양이 마치 물속 거품(bubble)과 닮았다

 

🔖 거의 모든 이벤트는 버블링 된다.

-> 키워드는 ‘거의’ 이다. focus 이벤트와 같이 버블링 되지 않는 이벤트도 존재

 

📍 event.target: 부모 요소의 핸들러는 이벤트가 정확히 어디서 발생했는지 등에 대한 자세한 정보를 얻을 수 있다.

이벤트가 발생한 가장 안쪽의 요소는 타깃(target) 요소라고 불리고, event.target을 사용해 접근할 수 있다.

event.target과 this(=event.currentTarget) 차이점

  • event.target은 실제 이벤트가 시작된 ‘타깃’ 요소. 버블링이 진행되어도 변하지 않는다.
  • this는 ‘현재’ 요소로, 현재 실행 중인 핸들러가 할당된 요소를 참조

 

form.onclick 핸들러 내의 event.target와 this

: form.onclick 핸들러 하나 안에서 폼 안의 모든 요소에서 발생하는 클릭 이벤트를 catch 잡아낸다. 클릭 이벤트가 어디서 발생했든 상관없이 <for> 요소까지 이벤트가 버블링 되어 핸들러를 실행시키기 때문

  • event.target – 폼 안쪽에 실제 클릭한 요소
  • this(event.currentTarget) – <form> 요소에 있는 핸들러가 동작했기 때문에 <form> 요소

 

📍 버블링 중단:  event.stopPropagation() 이용해 핸들러에게 이벤트를 완전히 처리하고 난 후 버블링을 중단하도록 명령

<body onclick="alert('여기까지 버블링 도달 못함')">
  <button onclick="event.stopPropagation()">click</button> // 버튼을 눌려도 alert 창이 뜨지 x
</body>

 

event.stopPropagation()은 위쪽으로 일어나는 버블링은 막지만 다른 핸들러 동작은 막지 못하는데, 다른 핸들러 동작도 막기 위해서는 event.stopImmediatePropagation()을 사용한다. 이 메서드를 사용하면 요소에 할당된 특정 이벤트를 처리하는 핸들러 모두가 동작하지 않는다.

 

🔖 버블링은 유용하다. 꼭 필요한 경우를 제외하곤 버블링을 막지 않도록!

아키텍처를 잘 고려해 진짜 막아야 하는 상황에서만 버블링을 막도록 하자. event.stopPropagation()은 추후에 문제가 될 수 있는 상황을 만들어낼 수 있다.

예를 들어 중첩 메뉴를 만들었다 가정하자. 각 서브메뉴(submenu)에 해당하는 요소에서 클릭 이벤트를 처리하도록 하고, 상위 메뉴의 클릭 이벤트 핸들러는 동작하지 않도록 stopPropagation을 적용한다. 사람들이 페이지에서 어디를 클릭했는지 등의 행동 패턴을 분석하기 위해, window내에서 발생하는 클릭 이벤트 전부를 감지하기 위해 분석 시스템을 도입하기로 한다. 그런데 이런 분석 시스템의 코드는 클릭 이벤트를 감지하기 위해 document.addEventListener('click'…)을 사용한다. stopPropagation로 버블링을 막아놓은 영역에선 분석 시스템의 코드가 동작하지 않기 때문에, 분석이 제대로 되지 않는다. 안타깝게도 stopPropagation을 사용한 영역은 '죽은 영역(dead zone)'이 되어버린다. 이벤트 버블링을 막아야 하는 경우는 거의 없다.

버블링을 막아야 해결되는 문제라면 커스텀 이벤트 등을 사용해 문제를 해결할 수 있다. 핸들러의 event 객체에 데이터를 저장해 다른 핸들러에서 읽을 수 있게 하면, 아래쪽에서 무슨 일이 일어나는지를 부모 요소의 핸들러에게 전달할 수 있으므로, 이 방법으로도 이벤트 버블링을 통제할 수 있다.

 

이벤트 캡쳐링(Event Capturing)

 

📍 이벤트 캡쳐링 원리: 버블링의 반대로 이벤트가 하위 요소로 전파. 버블링은 전달에 사용하였다면 캡쳐링은 탐색할 때 이용한다.

elem.addEventListener(..., {capture:true})
elem.addEventListener(..., true)

// 제거
elem.removeEventListener(..., true)

false가 default 값으로 핸들러는 버블링 단계에서 동작하는 것이고 {capture:true}또는 그냥 true값을 주면 캡쳐링 단계에서 동작한다.

 

https://ko.javascript.info/bubbling-and-capturing