하위요소에서 발생한 이벤트가 하위요소에서 상위요소로 전파된다.
이벤트가 거슬러 올라가는 모습이 물 속의 거품과 같아 이벤트 버블링이라고 한다.
대부분의 이벤트는 버블링으로 전파되지만 일부는 그렇지 않다. 만약 이 이벤트들이 발생했을 때 상위 요소에서 캐치하려면 우측의 이벤트들로 대체하면 된다.
동작은 같지만 버블링에서 차이가 난다.
이벤트 버블링은 stopPropagation()
으로 인위적으로 막을 수 있다. 하지만 막을 경우는 거의 없기에 자주 사용되지는 않는다.
이벤트 버블링을 활용하여 이벤트 위임을 할 수 있다.
이벤트 위임이란 자신에게서 발생하는 이벤트를 다른 요소에서 처리하는 것
for of를 이용해 모든 li에서 on클래스를 지고 클릭된 li에만 on클래스를 추가하여 빨간색을 보여주고 있다.
하지만 li가 많아질수록 코드도 길어지고, 성능도 안 좋아지고, 유지보수가 힘들어지는 등 문제가 있다.
그럴 때 li가 아닌 부모요소 ul에 이벤트를 위임할 수 있다.
위와 같이 ul의 이벤트핸들러를 등록하면 li의 개수가 얼마나 되든 코드 수정도 필요없어 유지보수에도 좋다.
이것이 가능한 이유는 버블링 덕이다. li에서 발생한 이벤트가 ul의 이벤트를 실행시키는 원리다.
하지만 문제가 있다.
위처럼 li에 링크를 추가하고 클릭하면 뭔가 이상하다.
li태그에 들어가있어야할 on이 a태그에도 들어가 있다. 콘솔로그 해보면
위와 같이 나오는데 이벤트핸들러에 등록된 currentTarget
과, 실제로 누른 target
이 일치하지 않아서다.
이벤트 위임을 사용하지 않았다면 누른 요소와 핸들러에 등록된 요소가 같다.
해결하기 위해 a태그를 눌러도 li에 클래스에 추가해주자.
target의 tagNmame가 A면 target의 부모요소 즉, li로 할당해준다. 그리고 target에 on을 추가해준다.
그리고 ul 부분. 그러니까 테두리를 클릭해도 색이 변한다. 조건을 하나 더 추가해주자.
클릭한 부분이 ul과 같다면(이전에 클릭해서 색깔이 변한 부분의 부모요소,
target.classList.add(“on”)) 그냥 리턴해준다.
기본적으로 React에서 사용되는 이벤트 처리 방식
1. 부모 요소에서 이벤트 처리
클릭한 리스트 아이템의 정보를 처리
const handleParentClick = (e) => {
if (e.target.tagName === "LI") {
alert(`You clicked on ${e.target.textContent}`);
}
};
return (
<ul onClick={handleParentClick}>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
);
2. 전파 차단 (e.stopPropagation)
const handleBackgroundClick = () => alert("모달 닫기");
const handleModalClick = (e) => e.stopPropagation();
return (
<div onClick={handleBackgroundClick}>
<div onClick={handleModalClick}>
<p>모달 내용</p>
</div>
</div>
);
이벤트를 상위 요소에서 먼저 처리해야 하는 경우에 사용
기본적으로 잘 사용되지 않는다.
DOM의 특정 하위 요소에서 이벤트를 무효화하거나 제어할 때 사용
const handleCapture = (e) => {
if (e.target.tagName === "INPUT") {
e.preventDefault(); // 모든 input의 기본 동작 차단
alert("입력 불가!");
}
};
return (
<div onClickCapture={handleCapture}>
<input type="text" placeholder="입력 불가" />
<button>버튼</button>
</div>
);
const handleCapture = (e) => {
console.log(`Captured event from ${e.target.tagName}`);
};
return (
<div onClickCapture={handleCapture}>
<button>버튼 1</button>
<button>버튼 2</button>
</div>
);
사용 방식 | 언제 사용? |
---|---|
버블링 | - 기본적인 이벤트 처리. - 부모에서 자식 이벤트를 처리하거나 차단 필요. - 대부분의 UI 상호작용 처리. |
캡처링 | - 이벤트를 상위 요소에서 먼저 처리해야 할 때. - 로깅, 추적, 조건부 차단. |
이벤트 캡처링
타겟 요소에 이벤트가 발생했을 때 최상위 요소부터 자식요소를 타고 이벤트가 가는 것
이벤트 버블링
타겟 이벤트가 실행한 후 다시 부모 요소를 타고 거슬러가는 것
event.stopPropagation()
이벤트의 전파를 막는 메소드
event.preventDefault()
태그의 기본동작을 막는 메소드(버튼태그의 클릭 이벤트 등)
addEventLisner의 기본 동작은 버블링이다.