본문 바로가기
Study

[article] You’ve Got Options for Removing Event Listeners

by 안자두 2023. 3. 7.

🌞 Article

👇 link

https://www.macarthur.me/posts/options-for-removing-event-listeners

 

You’ve Got Options for Removing Event Listeners

Reviewing some of the most common approaches available to remove event listeners in JavaScript.

www.macarthur.me

 

 


💬 정리하기

프로젝트를 진행하며 이벤트 리스너로 인한 문제가 발생했던 적이 종종 있었다.
예를 들면, (spa 프로젝트) 무한 스크롤을 구현하며 top 버튼으로 한 번에 상단 이동이 가능하도록 구현할 때 사용한 이벤트 리스너가, 다른 페이지로 이동한 후에도 해당 요소를 감지하려고 하여 에러가 난 적이 있었다.
당시에는 무엇이 문제인지 몰랐다가, 이후 다른 프로젝트를 진행하며 이 문제에 대한 해결방법이 생각나 뒤늦게 해결했던 경험이 있다.
단순히 useEffect() 내부에서 해당 리스너를 사용할 때, return으로 removeEventListener()를 호출해 주어 해결하였다.
결론적으로는 한 줄 추가에 그쳤지만, 당시에는 이유를 몰라 허둥댔던 기억이 있다.
그 경험 덕분에 이후 프로젝트부터는 더 이상 사용되지 않는 이벤트 리스너에 주의를 기울이게 되었다.😂

아무튼, 그 기억을 떠올리며 글을 읽어보았다.

 

첫 번째로는 우선 기본적으로는 removeEventListener()를 사용하여 직접적으로 리스너를 제거할 수 있다.

여기서는 그 외의 방법들도 소개하고 있는데, 개중 나에게 가장 사용 가능성이 높아보인 것은, addEventListener()의 once 옵션이었다.
이름처럼 once 옵션의 값을 true로 설정하면 리스너가 처음 호출된 후, 자동으로 제거된다.
익명 함수를 사용하려고 하는 경우를 사용 사례로 들고 있다.

const button = document.getElementById('button');

button.addEventListener('click', () => {
	console.log('clicked!');
}, { once: true });

// 'clicked!'
button.click();

// No more listeners!
getEventListeners(button) // {} 

 

세 번째로는 노드 자체를 교체하는 방법을 들었다. 노드를 복제한 후, 해당 노드로 갈아치우는 방식인데, 이 방식의 단점으로는 근본적인 리스너는 유지가 된다는 점이다.

button.parentNode.replaceChild(button.cloneNode(true), button);
// 또는
button.replaceWith(button.cloneNode(true));

아래처럼 속성이 내재돼있다면 여전히 onclick 이벤트가 실행된다는 말이다.

<button id="button" onclick="console.log('clicked!')">
	Do Something
</button>

 

그리고 마지막으로는 나에게도 가장 새로웠던 AbortController()였다.

AbortController()의 signal을 addEventListener()의 속성으로 추가한 후, 제거를 원할 때 각 controller가 abort()를 호출하면, signal이 리스너가 제거되도록 트리거한다.
이 방법의 이점은 하나의 signal을 사용하여 모든 종류의 리스너를 제거할 수 있다는 점이다.

const button = document.getElementById('button');
const controller = new AbortController();
const { signal } = controller;

button.addEventListener('click', () => console.log('clicked!'), { signal });
window.addEventListener('resize', () => console.log('resized!'), { signal });
document.addEventListener('keyup', () => console.log('pressed!'), { signal });

// Remove all listeners at once:
controller.abort();

이 방법의 단점은 브라우저 호환성에 있다. 2021년(v90) 이후에만 chrome에서 지원된다고 한다.

 

상황에 따라 필요한 방법을 쓸 수 있다.

- removeEventLister()의 경우에는 callback()이 변수에 할당되어 리스너가 추가된 위치에 쉽게 도달할 수 있는 경우 사용
- once옵션의 경우는 callback()을 한 번만 실행할 때
- 요소를 복제하고 교체하는 방법은 하나에 여러 리스너가 바인딩되어 있는 경우
- AbortController()는 한 번의 명령으로 여러 리스너를 제거해야 할 때

 

추가적으로 댓글을 통해 알게 된 점은 인라인 리스너의 경우는 요소에서 속성을 부팅하여 제거할 수 있다고 한다.

document.getElementById('button').removeAttribute('onclick');
// 또는
document.getElementById('button').onclick = null;

 

728x90