Javascript & Typescript/이해하기

[JS] 이벤트 버블링, 이벤트 캡처링, 이벤트 위임 이해하기

adjh54 2022. 10. 10. 01:12
반응형
해당 글에서는 브라우저가 이벤트를 감지하는 방법을 이해하기 위한 목적으로 이벤트 버블링, 이벤트 캡쳐링, 이벤트 위임에 대해 이해합니다.

 

💡 해당 방식에서는 'React'를 기준으로 작성하였기에 'addEventListener'를 이용한 이벤트 처리 방식을 사용하지 않고 예시를 작성하였습니다.

 

 

[참고] React 공식 사이트 
 

이벤트 처리하기 – React

A JavaScript library for building user interfaces

ko.reactjs.org

 

 

1) 이벤트 버블링(Event Bubbling) 


출처: https://www.robinwieruch.de/react-event-bubbling-capturing/

💡 이벤트 버블링(Event Bubbling)이란?

- 특정 화면 요소에서 이벤트가 발생하였을 때, 해당 이벤트가 발생하는 위치뿐만 아니라 상위의 화면 요소들로 전파되는 특성을 의미합니다.
- 이 전파되는 특성은 하위 요소 → 상위 요소들로 전달이 됩니다.

 

 

💡 이벤트 버블링(Event Bubbling)의 예시

- 사용자는 '최하위 요소라는 영역'을 클릭하였습니다.
예상된 결과로는 콘솔에 “최하위 요소가 호출되었습니다.”라고만 출력이 되어야 합니다. 그러나 상위 요소까지 전파가 되어서 모든 요소들이 콘솔로 출력이 되었습니다. 이러한 최하위 요소 -> 상위 요소로 전파되는 특성을 이벤트 버블링이라고 합니다.

 

const EventBubbling = () => {

    const onClickParent = () => console.log("상위 요소가 호출되었습니다.")
    const onClickChild = () => console.log("하위 요소가 호출되었습니다.")
    const onClickLowestChild = () => console.log("최하위 요소가 호출되었습니다.")

    /**
     * 상위 요소를 클릭하면 하위 메소드까지 호출되도록 처리 
     */
    return (
        <div>
            <div style={{ backgroundColor: "red", width: 250 }} onClick={onClickParent} >상위 요소
                <div style={{ backgroundColor: "blue", width: 250 }} onClick={onClickChild}>하위 요소
                    <div style={{ backgroundColor: "yellow", width: 250 }} onClick={onClickLowestChild}>최하위 요소</div>
                </div>
            </div>
        </div>
    )
}
export default EventBubbling;

 

 [더 이해하기]
💡 이벤트 버블링의 과정

- 브라우저는 선택된 요소가 버블링 단계에 대해 그것에 등록된 onclick 이벤트 핸들러를 가지고 있는지 확인하기 위해 검사하고 만약 그렇다면 실행합니다. 그리고 그것은 바로 다음의 조상 요소로 이동하고 같은 일을 하고 그리고서 그다음 요소로 이동하고 <html> 요소에 닿을 때까지 계속 수행됩니다.

 

[참고] MDN 이벤트 버블링
 

이벤트 입문 - Web 개발 학습하기 | MDN

이벤트(event)란 여러분이 프로그래밍하고 있는 시스템에서 일어나는 사건(action) 혹은 발생(occurrence)인데, 이는 여러분이 원한다면 그것들에 어떠한 방식으로 응답할 수 있도록 시스템이 말해주

developer.mozilla.org

 

 

2) 이벤트 캡처링(Event Capturing)


출처: https://www.robinwieruch.de/react-event-bubbling-capturing/

💡 이벤트 캡처링(Event Capturing)이란?

- 특정 화면 요소에서 이벤트가 발생하였을 때, 해당 이벤트가 발생하는 위치뿐만 아니라 하위의 화면 요소들로 전파되는 특성을 의미합니다.
- 이 전파되는 특성은 상위 요소 → 하위 요소들로 전달이 됩니다.
💡 이벤트 캡처링(Event Capturing) 예시

- 사용자는 '상위 요소라는 영역'을 클릭하였습니다.
예상된 결과로는 콘솔에 “상위 요소가 호출되었습니다.” 라고만 출력이 되어야 합니다. 그러나 하위 요소까지 전파가 되어서 모든 요소들이 콘솔로 출력이 되었습니다. 이러한 상위 요소-> 최하위 요소로 전파되는 특성을 이벤트 캡처링이라고 합니다.

 

 

const EventCapturing = () => {

    const onClickParent = () => console.log("상위 요소가 호출되었습니다.")
    const onClickChild = () => console.log("하위 요소가 호출되었습니다.")
    const onClickLowestChild = () => console.log("최하위 요소가 호출되었습니다.")

    return (
        <div>
            <div style={{ backgroundColor: "red", width: 250 }} onClickCapture={onClickParent} >상위 요소
                <div style={{ backgroundColor: "blue", width: 250 }} onClickCapture={onClickChild}>하위 요소
                    <div style={{ backgroundColor: "yellow", width: 250 }} onClickCapture={onClickLowestChild}>최하위 요소</div>
                </div>
            </div>
        </div>
    )

}
export default EventCapturing;

 

[더 이해하기]

💡 이벤트 캡처링의 과정

- 브라우저는 요소의 가장 바깥쪽의 조상(<html>)이 캡처링 단계에 대해 그것에 등록된 onclick 이벤트 핸들러가 있는지를 확인하기 위해 검사하고 만약 그렇다면 실행합니다. 그리고 <html> 내부에 있는 다음 요소로 이동하고 같은 것을 하고, 그리고서 그 다음 요소로 이동하고, 실제로 선택된 요소에 닿을 때까지 계속 수행합니다.
 

이벤트 입문 - Web 개발 학습하기 | MDN

이벤트(event)란 여러분이 프로그래밍하고 있는 시스템에서 일어나는 사건(action) 혹은 발생(occurrence)인데, 이는 여러분이 원한다면 그것들에 어떠한 방식으로 응답할 수 있도록 시스템이 말해주

developer.mozilla.org

 

 

3) 이벤트 버블링, 캡처링 중단


💡 이벤트 버블링이 발생함에 따라서 이를 중단하는 메서드는 event.stopPropagation() 메서드를 사용합니다.
💡 이 메서드는 이벤트 캡처링 혹은 버블링에서 핸들러의 이벤트 객체가 호출되었을 때, 이는 첫 번째 핸들러가 실행되지만 이벤트가 더 이상 위로 전파되지 않도록 만들어서 더 이상의 핸들러가 실행되지 않도록 합니다.

 

 

1. 이벤트 버블링 중단


💡 해당 소스 코드에서는 “최하위 요소”, “하위 요소”, “상위 요소”를 클릭 했을 경우, 이벤트 버블링이 동작하지 않고 각각에 맞는 콘솔이 출력됨이 확인되었습니다.

 

const EventBubbling = () => {

    const onClickParent = (e) => {
        e.stopPropagation();
        console.log("상위 요소가 호출되었습니다.")
    }
    const onClickChild = (e) => {
        e.stopPropagation();
        console.log("하위 요소가 호출되었습니다.")
    }
    const onClickLowestChild = (e) => {
        e.stopPropagation();
        console.log("최하위 요소가 호출되었습니다.");
    }
    return (
        <div>
            <div style={{ backgroundColor: "red", width: 250 }} onClick={(e) => onClickParent(e)} >상위 요소
                <div style={{ backgroundColor: "blue", width: 250 }} onClick={(e) => onClickChild(e)}>하위 요소
                    <div style={{ backgroundColor: "yellow", width: 250 }} onClick={(e) => onClickLowestChild(e)}>최하위 요소</div>
                </div>
            </div>
        </div>
    )
}
export default EventBubbling;

 

 

2. 이벤트 캡처링 중단


💡  해당 소스 코드에서는 “최하위 요소”, “하위 요소”, “상위 요소”를 각각 클릭 했을 경우, 이벤트 캡처링이 동작하지 않고 오직 “상위 요소가 호출되었습니다”라고 콘솔에 출력이 되었습니다.
💡 이는 onClickCapture()로 최상위 캡처만 보고 있기에 전파가 되지 않고 상위 요소만 호출이 되는 경우입니다

 

 

const EventCapturing = () => {

    const onClickParent = (e) => {
        e.stopPropagation();
        console.log("상위 요소가 호출되었습니다.")
    }
    const onClickChild = (e) => {
        e.stopPropagation();
        console.log("하위 요소가 호출되었습니다.")
    }
    const onClickLowestChild = (e) => {
        e.stopPropagation();
        console.log("최하위 요소가 호출되었습니다.");
    }
    return (
        <div>
            <div style={{ backgroundColor: "red", width: 250 }} onClickCapture={(e) => onClickParent(e)} >상위 요소
                <div style={{ backgroundColor: "blue", width: 250 }} onClickCapture={(e) => onClickChild(e)}>하위 요소
                    <div style={{ backgroundColor: "yellow", width: 250 }} onClickCapture={(e) => onClickLowestChild(e)}>최하위 요소</div>
                </div>
            </div>
        </div>
    )
}
export default EventCapturing;

 

4) 이벤트 위임 - Event Delegation


💡 캡처링과 버블링을 활용하여서 이벤트 핸들링의 패턴인 이벤트 위임을 구현 할수 있습니다. 이는 엘리먼트 마다 모든 이벤트 리스너를 만들어야 하는 번거로움이 있습니다. 이러한 동작을 최소화 하기 위하여 이벤트 위임을 사용합니다.

 

 

💡 이벤트 캡쳐링, 버블링을 공부를 하였습니다.
사실상 이벤트 위임을 위한 캡처링 상황과 버블링 상황을 이해하여 효율적은 소스코드를 작성하기 위함이었으나,
React 내부 자체에서는 이미 이벤트 위임을 수행하고 있고 또한 성능에 이점이 없다고 아래의 글들이 이야기하고 있습니다.
그렇다면, 이벤트 위임에 대한 원리만 이해하시면 좋을 것 같습니다.

 

 

Should I use event delegation in React?

What is event delegation? Event delegation is a performance optimization method in the wor...

dev.to

 

 

Event delegation in React · Issue #13635 · facebook/react

Given that React does attach event handlers to the nodes themselves, does the React team recommend app developers to do event delegation when working with large lists for saving memory? Something l...

github.com

 

💡 대표적인 예시가 있습니다.
- document 내에서 click 이벤트가 발생할 경우 만약 속성 중 data속성의 counter라는 값이 존재한다면 값을 올려주는 예제입니다. 이 예제에서는 document라는 공간에서 특정 요소(data-counter)라는 값만 찾아서 이벤트를 수행시키는 방식으로 처리가 됩니다.
- 위에서 이야기 했던것 처럼 이벤트 위임은 이점이 없습니다. 이미 처리를 해주고 있고, 각각 엘리먼트에 on~ 이벤트로 처리만 해주면 될것 같습니다
첫 번째 카운터: <input type="button" value="1" data-counter>
두 번째 카운터: <input type="button" value="2" data-counter>

<script>
  document.addEventListener('click', function(event) {
    if (event.target.dataset.counter != undefined) { // 속성이 존재할 경우
      event.target.value++;
    }

  });
</script>

 

오늘도 감사합니다😀

반응형