JS | 이벤트 플로우를 갖고 노는 법

연이·2022년 11월 21일
1

JavaScript

목록 보기
4/4
post-thumbnail

📌 스터디 미니 발표회 러버덕스 첫번째 꽥에서 발표한 내용을 담은 포스팅입니다. 최대한 발표 현장에서 진행한 순서를 담아 작성한 포스팅(반복하여 정리하는 부분들이 있습니다...😂)인 점 참고 부탁드립니다~!
🔗 발표 자료 link


1. Event Flow

이벤트 플로우란 어떤 요소에서 이벤트가 발생했을 때, 그 이벤트를 전파하여 감지하는 흐름을 말한다.

이렇게 정의만 봤을 때는 이벤트 플로우가 뭔지 제대로 느낌을 잡기가 어려운 것 같다. 다음 코드를 통해 이벤트 플로우를 제대로 이해해 보도록 하자!


<div>
	<ul>
		<li>과연 li의 클릭 이벤트만 실행이 될까?</li>
	</ul>
</div>

li 요소에 클릭 이벤트를 등록시키고 실행하였을 때, li의 클릭 이벤트만 실행이 될까? 상위 요소인 uldiv에는 아무런 현상도 일어나지 않을까?


document.querySelector('li').addEventListener('click', () => console.log('1. li 클릭됨'))
document.querySelector('ul').addEventListener('click', () => console.log('2. ul 클릭됨'))
document.querySelector('div').addEventListener('click', () => console.log('3. div 클릭됨'))

위의 궁금증을 해결하기 위해서 각각의 요소에 click 이벤트를 등록해 보고 실행해 보았다.


👆🏻 실행영상 보러가기

분명 li요소만 클릭했음에도 불구하고 ul 요소와 div 요소의 클릭 이벤트도 실행된 것을 확인할 수 있다. 그리고 1 2 3의 순서가 일정한 것을 통해 사이좋게 실행 되더라도 먼저 실행되는 이벤트가 있다는 것도 확인할 수 있다. 이 이벤트들이 실행되는 순서이벤트 플로우라고 한다.



2. Event Propagation(이벤트 전파)

우리는 앞에서 이벤트가 실행되는 순서가 있다는 것을 확인하였다. 하지만 생각해보니 궁금증이 더 생기는 것 같다.

💡 위의 코드처럼 모든 요소에 이벤트가 등록되어 있다면 누구를 먼저 실행 시킬 건데? 그래서 어떤 순서로 실행이 되는 건데?

이 궁금증 해결을 위해 이벤트 전파인 Event Propagation에 대해 알아보도록 하자.


이벤트 전파는 이벤트 객체가 전파되는 방향에 따라 캡처링, 타겟, 버블링의 3단계로 진행된다.

이 코드를 다시 한번 봐보도록 하자. li는 부모 요소로 ul을, ul은 부모 요소로 div를 가지고 있다. div의 부모 요소는 Body이고, Body의 부모 요소는 HTML이다. 이런 식으로 DOM 트리를 타고 올라가다가 보면,

이와 같은 구조가 완성이 된다.


2-1. 캡처링

이벤트의 전파는 브라우저에서 가장 가까운 요소에서부터 시작되는 규칙을 가지고 있다. 따라서 브라우저와 가장 가까운 요소인 window에서부터 이벤트가 발생하기 시작해서 아래로 쭉 찍고 내려오면서 타겟 요소인 li까지 내려오게 된다. 이 과정을 이벤트 캡처링이라고 부른다.


이벤트 캡처링은 이벤트가 상위 요소에서 하위 요소 방향으로 전파되는 것을 말한다.

✅ 이해를 돕기 위한 막무가내 예시 (1. 캡처링)
어떤 이벤트를 위해 이벤트 준비 브이로그를 찍는다고 해보자. 이벤트 D-Day로 정한 그 날짜까지 열심히 그 과정들을 기록(캡처)한다고 기억해 보자. 😅


2-2. 타겟

두 번째 단계인 타겟 단계는 이벤트가 진짜 발생한 이벤트 타겟에 도달해 시벤트가 실행되는 것을 말한다.

✅ 이해를 돕기 위한 막무가내 예시 (2. 탸겟)
이벤트 준비 브이로그를 찍으면서 열심히 준비하다보면 이벤트 D-Day가 다가와 이벤트를 열어주게 된다! (타겟)


2-3. 버블링

마지막으로 버블링 단계는 이벤트가 발생한 최하위 요소에서 상위 요소엔 window까지 이벤트가 전파되는 과정을 말한다.

✅ 이해를 돕기 위한 막무가내 예시 (3. 버블링)
이벤트를 성공적으로 마치고 기분 좋은 마음으로 집에 와서 샤워를 해봅시다. 기분 좋은 날이니까 러쉬에서 입욕제를 사서 왔어요. ㅋㅋㅋ 입욕제를 욕조에 넣으면 거품이 보글보글 위로 올라오잖아요?(버블링) 이렇게 막무가내로 기억해 봅시다.


2-4. 이벤트 전파의 3단계 정리

이벤트 리스너가 동작하면 캡처링과 버블링이 발생한다. 첫 번째 단계로 이벤트가 상위 요소에서 하위 요소로 전파되는 캡처링 단계가 일어나고, 이벤트가 진짜 발생한 타깃에 도달해 이벤트가 실행이 되면, 하위 요소에서 상위 요소 방향으로 이벤트가 전파되는 버블링 단계가 일어난다.



3. Event Delegation (이벤트 위임)

혹시 이번 포스팅의 제목이 '이벤트 플로우를 갖고 노는 법'이라는 걸 기억하고 있는 분들이 있는가? 지금까지 이벤트 플로우에 대해서 알아봤다면 이제 진짜 가지고 노는 법을 알아볼 차례다. 이벤트 위임에 대해 알아보도록 하자.


3-1. target vs currentTarget

이벤트 위임에 대해 본격적으로 알아보기 전에 target과 currentTarget에 대한 이해가 필요하다.
current target이벤트의 진짜 주인 즉, 이벤트 리스너를 가진 요소를 말하고, target이벤트의 시발점 즉, 이 이벤트가 발생한 요소를 말한다.

늘 그랬듯 정의만 봐서는 이해가 쉽지 않기 때문에 예시를 같이 보도록 하자.


<div>
    <ul>
        <li>과연 li의 클릭 이벤트만 실행이 될까?</li>
    </ul>
</div> 
document.querySelector('li').addEventListener('click', () => console.log('1. li 클릭됨'))
document.querySelector('ul').addEventListener('click', () => console.log('2. ul 클릭됨'))
document.querySelector('div').addEventListener('click', () => console.log('3. div 클릭됨'))

우리는 위에서 li를 클릭하여 이벤트를 실행했을 때 상위 부모 요소까지 이벤트가 실행되고 있는 것을 확인을 했다.


li를 클릭했을 때 li의 입장에서 보면 이벤트 주인(currentTarget)은 자기 자신인 li가 되고, 이벤트가 본인 때문에 시작한 것이기 때문에 이벤트의 시발점(target) 또한 li가 된다.

따라서 currentTarget과 target이 동일하게 li가 되게 된다.


그렇다면 ul의 입장에서 봐보도록 하자. ul의 입장에서 보면 이벤트 리스너를 가지고 있는 이벤트의 주인(currentTarget)은 ul이 되게 된다. 하지만 li의 이벤트가 실행 되었기 때문에 ul의 이벤트가 발생한 것이므로 이벤트의 시발점(target)은 li가 되게 된다. 또,li와는 달리 ul은 currentTarget과 target이 다르다.


ul과 마찬가지로 div도 currentTarget, 이벤트를 가지고 있는 진짜 주인은 div가 되고, target, 이벤트가 시작된 시발점은 li가 되게 된다.


3-2. Event Delegation (이벤트 위임)

이벤트 전파와 target에 대한 이해가 충분히 되었다면 이제 진짜 이벤트 위임에 대해 알아볼 차례가 되었다. 이벤트 위임은 여러 개의 하위 DOM 요소에 각각 이벤트 핸들러를 등록하는 대신, 하나의 상위 DOM 요소에 이벤트 핸들러를 등록하는 방법을 말한다.


<div>
    <ul>
        <li id="one">1. 떡볶이</li>
        <li id="two">2. 피자</li>
        <li id="three">3. 햄버거</li>
    </ul>
</div>
const one = document.querySelector('#one')
const two = document.querySelector('#two')
const three = document.querySelector('#three')

function listEvent() {
    console.log('클릭됨')
}

one.addEventListener('click', listEvent)
two.addEventListener('click', listEvent)
three.addEventListener('click', listEvent)

원래 같았으면 우리는 위처럼 각각의 li에 아이디를 달아서 이벤트를 등록해 주었을 것이다. 그렇지만 각각의 요소에 이벤트를 등록하는 방법이 솔직히 조금 귀찮기도하고, 활용성도 좋아보이지는 않는다. 이럴 때 이벤트 위임을 사용해 주면 ul 요소에만 이벤트를 등록해 주어도 li 요소에 각각 이벤트를 등록해 준 것과 똑같이 동작하게 만들 수가 있다.

이벤트 위임은 이벤트 버블링이라는 전파 과정이 있기 때문에 가능한 방법이다. 이벤트 위임을 사용해 위의 각각의 요소에 이벤트를 달아 준 코드를 개선해 보도록 하겠다.

<div>
    <ul id="listItem">
        <li>1. 떡볶이</li>
        <li>2. 피자</li>
        <li>3. 햄버거</li>
    </ul>
</div>
const ul = document.querySelector('#listItem')

function listEvent(event) {
    if (event.target.tagName == 'LI') {
        console.log('ul 클릭했는데 클릭됨')
    }
}

ul.addEventListener('click', listEvent)

✅ 공통 부모에 할당한 핸들러에서 event.target을 사용하면 실제 어디서 이벤트가 발생했는지 알 수 있다.

코드가 훨씬 간결해 졌다는 인상이 들지 않는가? 이벤트 버블링과 target 속성을 이용해서 '만약 내가 누른 것의 태그 네임이 li라면 콘솔에 'ul 클릭했는데 클릭됨' 출력해 줘. 라는 함수를 ul에 등록시키기만 했는데도 아까와 같은 동작을 할 수 있게 되었다.


3-3. 이벤트 위임의 장점

이벤트 위임에 대해 위에서 간단하게 알아 보았다. 이벤트 위임을 사용하면

    1. 동적으로 엘리먼트를 추가할 때마다 핸들러를 고려할 필요가 없다
    1. 메모리 공간 사용량이 줄어든다
    1. 코드가 훨씬 깔끔해진다

등등의 장점은 있지만, 무조건 이벤트 위임이 좋은 것은 아니기 때문에 상황에 맞게 잘 사용하도록 하는 것이 중요하다.
또 이벤트 위임은 앞에서 언급했다시피 버블링이 가능할 때만 사용할 수 있기 때문에 주의를 요한다. focus 같은 이벤트는 버블링이 일어나지 않는다.



4. 면접에 대비해 보자!

📌 이번 발표를 준비하면서 주제를 정하기 위해 FE 기술 면접 레포지토리들을 많이 탐색하면서 다녔다. 이벤트 플로우 개념을 사용해 기능을 구현하는 것이 사실 실무에서는 많이 쓰이는 방법은 아니라고 한다. 그럼에도 불구하고 이벤트 플로우, 이벤트 위임에 대한 주제를 정한 것은 꽤 높은 빈도(5점 만점에 3.5-4점)로 관련 질문이 면접에서 다뤄지고 있다고 생각했기 때문에 같이 공부해 보면 좋을 것 같아서 정하게 되었다.

마무리로, 같은 주제 내에서 가장 많은 빈도로 면접에서 다뤄지는 문제들을 정리하면서 포스팅을 마무리하고자 한다. (매우 주관적)

4-1. 이벤트 버블링과 캡처링이 무엇인가요?

이벤트 버블링이란, 하위 엘리먼트에 이벤트가 발생할 때 그 엘리먼트부터 시작해서 상위 요소까지 이벤트가 전달되는 방식을 말하고.

이벤트 캡처링이란, 하위 엘리먼트에 이벤트 핸들러가 있을 때 상위 엘리먼트부터 이벤트가 발생하기 시작해서 하위 엘리먼트까지 이벤트가 전달되는 방식을 말한다.


4-2. 이벤트 버블링을 어떻게 활용할 수 있나요?

이벤트 버블링을 활용하면 이벤트 위임이라는 방법을 사용할 수 있다.

동일한 이벤트를 일일히 수동으로 달아 주기에는 코드 낭비가 너무 심하기 때문에, 부모 요소에 이벤트를 부여해 버블링을 통해 하위 요소를 동작 시킬 때도 해당 이벤트가 발생하도록 만드는 이벤트 위임을 사용한다.



참고 자료

🔗 [GitHub] baeharam/Must-Know-About-Frontend
🔗 [GitHub] Esoolgnah/Frontend-Interview-Questions
🔗 [Youtube] 김버그님 | DOM 이벤트 플로우 완벽하게 정리해드립니다.

profile
💻 Front-end 개발자 지망생 연이입니다. 🚀

0개의 댓글