이벤트 위임(event delegation)

micrite·2023년 7월 10일

JavaScript

목록 보기
1/3
post-thumbnail

이벤트 위임이란?

버블링을 활용하여 하나의 이벤트 핸들러에서 다른 요소의 이벤트 동작을 다룰 수 있는 패턴을 이벤트 위임(event delegation)이라고 합니다.

어떻게 동작하는가?

아래와 같이 div 안에 같은 버튼이 4개가 있다고 합시다.

function foo() {
	return (
        <div>
          <button css={css({
            display: 'flex', 
            justifyContent: 'center', 
            itemsAlign: 'center', 
            width: '80px', 
            height: '80px',
            backgroundColor: 'red'
          })>
            <div css={css({
              width: '50px',
              height: '50px',
              backgroundColor: 'blue'
            })} />
          </button>
          <button>...</button>
          <button>...</button>
          <button>...</button>
        </div>
    );
}

button을 클릭할 때마다 작동하게 하려면 handleClick 핸들러를 4개를 작성해야 할 것입니다.

하지만, 다음과 같이 맨 위의 div 요소에 handleClick 핸들러 하나만을 작성해도 그 아래에 있는 Button에 핸들러를 작성한 것과 같은 효과를 적용할 수 있습니다.

function foo() {
  
  	const handleClick = (event) => {
    	if (event.target instanceof HTMLButtonElement) {
        	// ...
        }
    }
  
	return (
        <div onClick={handleClick}>
          <button>...</button>
          <button>...</button>
          <button>...</button>
          <button>...</button>
        </div>
    );
}

이것이 가능한 이유는 button 요소에서 div요소로 이벤트 버블링이 발생했기 때문입니다.

즉, 하위 요소에서 상위 요소로 이벤트가 전파되었습니다.

이번에는 button 요소 안의 div요소를 클릭했다고 해봅시다.

앞서 본 css에서 buttondiv 사이에는 상하좌우 30px 만큼의 간격이 존재하므로 충분히 div요소를 클릭할 수 있습니다.

안쪽의 div를 클릭했을 때에도 button을 클릭한 것처럼 동작하게 하고 싶다면, closest를 사용합니다.

function foo() {
  
  	const handleClick = (event) => {
    	if (event.target instanceof HTMLDivElement) {
        	const btn = event.target.closest('button');
          	if (event.target === event.currentTarget) {
            	return;
            }
            if (!btn) {
            	return;
            }
          	
          	// ...
        }
    }
  
	return (
        <div onClick={handleClick}>
          <button>...</button>
          <button>...</button>
          <button>...</button>
          <button>...</button>
        </div>
    );
}

코드를 설명해보자면, handleClick은 event.target이 HTMLDivElement 일때 작동하게 됩니다.

div요소는 맨 위에 핸들러가 할당된 요소와 button 컴포넌트 안에 할당되어 있는 요소 4개가 있습니다.

이를 구분하기 위해서 현재 핸들러가 할당된 맨 위의 요소 event.currentTarget과 같으면 더이상 진행하지 않게 됩니다.

data-* 적용하기

위의 패턴도 충분히 좋지만 더 간단하게 적용하고 싶다면 data-*를 각 요소에 전달해 볼 수 있습니다.

function foo() {
  
  	const handleClick = (event) => {
    	const bar = event.target.dataset.bar;
      	if (!bar) {
        	return;
        }
      	// ...
    }
  
	return (
        <div onClick={handleClick}>
          <button data-bar="bar1">...</button>
          <button data-bar="bar2">...</button>
          <button data-bar="bar3">...</button>
          <button data-bar="bar4">...</button>
        </div>
    );
}

이벤트 위임의 장점과 단점

장점

  • 핸들러를 많이 작성하지 않아도 되기 때문에 메모리가 절약됩니다.

단점

  • 이벤트가 반드시 버블링 되어야 하므로 event.stopPropagation()을 쓸 수 없습니다.
  • 하위 요소에서 발생하는 모든 이벤트에 응답해야 합니다.
profile
안녕하세요

0개의 댓글