[JS] addEventListener가 손에 잘 안 익어서 정리해봤다

·2024년 9월 21일

Study Note ✍🏻

목록 보기
26/60

addEventListener

element.addEventListener(event, callback, options);

element : 해당 이벤트를 적용할 DOM
event : 이벤트 타입 (대표적으로 click, DOMContentLoad, scroll, submit)
callback : 이벤트를 발생시켰을 시 호출될 함수
options : (선택) 이벤트의 추가 설정

하나의 이벤트 대상에 복수의 동일 이벤트 타입 리스너를 등록할 수 있다.

const t = document.getElementById('target');

t.addEventListener('click', function(event){
	alert(1);
});

t.addEventListener('click', function(event){
	alert(2);
});

options에는 다음과 같은 값들이 있다.

capture: 버블링 단계가 아닌 캡처링 단계에서 이벤트를 처리할지 (default = false)
once: 이벤트가 한 번만 발생하면 자동으로 이벤트 리스너를 제거 (default = false)
passive: preventDefault를 호출하지 않는다. (default = false)

event

마우스 이벤트

click: 요소를 클릭할 때 발생합니다.
dblclick: 요소를 더블 클릭할 때 발생합니다.
mousedown: 마우스 버튼이 눌릴 때 발생합니다.
mouseup: 마우스 버튼이 떼질 때 발생합니다.
mouseover: 마우스가 요소 위로 이동할 때 발생합니다.
mouseout: 마우스가 요소에서 벗어날 때 발생합니다.
mousemove: 마우스가 요소 위를 움직일 때 발생합니다.
mouseenter: 마우스가 요소에 들어올 때 발생합니다. 이 이벤트는 자식 요소로 이동할 때 발생하지 않으며, 상위 요소에서 하위 요소로의 이동에서는 발생하지 않습니다.
mouseleave: 마우스가 요소를 떠날 때 발생합니다. 이 이벤트는 자식 요소로 이동할 때 발생하지 않으며, 상위 요소에서 하위 요소로의 이동에서는 발생하지 않습니다.
contextmenu: 마우스 오른쪽 버튼을 클릭하여 컨텍스트 메뉴를 열 때 발생합니다.
drag: 요소를 드래그할 때 발생합니다.
dragstart: 드래그가 시작될 때 발생합니다.
dragend: 드래그가 끝날 때 발생합니다.
dragenter: 드래그하는 요소가 대상 요소에 들어올 때 발생합니다.
dragleave: 드래그하는 요소가 대상 요소를 떠날 때 발생합니다.
dragover: 드래그된 요소가 대상 요소 위를 지나갈 때 발생합니다.
drop: 드래그한 요소를 대상 요소에 놓을 때 발생합니다.

키보드 이벤트

keydown: 키가 눌릴 때 발생합니다.
keyup: 키가 떼질 때 발생합니다.
keypress: 키가 눌리고 글자 입력이 이루어질 때 발생합니다. (권장되지 않음)

폼 이벤트

submit: 폼이 제출될 때 발생합니다.
reset: 폼이 리셋될 때 발생합니다.
change: 폼 요소의 값이 변경될 때 발생합니다.
input: 폼 요소에 값이 입력될 때 발생합니다.
focus: 요소가 포커스를 받을 때 발생합니다.
blur: 요소가 포커스를 잃을 때 발생합니다.
select: 텍스트가 선택될 때 발생합니다.
invalid: 폼 요소의 값이 유효하지 않을 때 발생합니다.

윈도우 이벤트

resize: 브라우저 창의 크기가 변경될 때 발생합니다.
scroll: 스크롤이 발생할 때 발생합니다.
online: 네트워크가 온라인 상태로 전환될 때 발생합니다.
offline: 네트워크가 오프라인 상태로 전환될 때 발생합니다.
error: 스크립트, 이미지 로드 실패 등으로 인해 오류가 발생할 때 발생합니다.
message: 웹 소켓 또는 다른 메시지 기반 API에서 메시지가 수신될 때 발생합니다.
storage: 웹 스토리지에 변경이 있을 때 발생합니다.

문서 이벤트

DOMContentLoaded: 문서의 HTML이 완전히 로드되고 파싱된 후 발생합니다.
load: 문서와 모든 자원(스타일시트, 이미지 등)이 완전히 로드된 후 발생합니다.
beforeunload: 페이지를 떠나기 전에 발생합니다.
unload: 문서가 언로드될 때 발생합니다. (권장되지 않음)

터치 이벤트 (모바일 장치)

touchstart: 터치가 시작될 때 발생합니다.
touchend: 터치가 끝날 때 발생합니다.
touchmove: 터치가 이동할 때 발생합니다.
touchcancel: 터치가 취소될 때 발생합니다.

제스처 이벤트 (모바일 장치)

gesturestart: 제스처가 시작될 때 발생합니다.
gesturechange: 제스처가 변경될 때 발생합니다.
gestureend: 제스처가 끝날 때 발생합니다.

비디오/오디오 이벤트

play: 비디오나 오디오가 재생될 때 발생합니다.
pause: 비디오나 오디오가 일시 정지될 때 발생합니다.
ended: 비디오나 오디오가 끝날 때 발생합니다.
volumechange: 볼륨이 변경될 때 발생합니다.
timeupdate: 현재 재생 시간이 업데이트될 때 발생합니다.
canplay: 비디오나 오디오가 재생 가능한 상태가 되었을 때 발생합니다.
canplaythrough: 비디오나 오디오가 버퍼링 없이 재생 가능한 상태가 되었을 때 발생합니다.
waiting: 비디오나 오디오의 재생이 중지되고 버퍼링이 필요할 때 발생합니다.

클립보드 이벤트

copy: 클립보드에 복사될 때 발생합니다.
cut: 클립보드로 잘려질 때 발생합니다.
paste: 클립보드에서 붙여넣기 될 때 발생합니다.

onClick과 비교

브라우저의 호환성 면에서 onClick 메소드는 모든 브라우저와 버전에서 호환되는데 비해
addEventListener는 IE 8 이하 버전에서는 호환되지 않는다. 호환성에 신경쓰고 싶지 않다면 OnClick 메소드를 사용하는 것이 바람직하다.

onClick 메소드는 구현할 기능인 function()만 받는데 비해 addEventLister는 3번째 파라미터로 버블링, 캡쳐링 동작 여부를 정할 수 있다. 이 설정을 통해 동작을 버블링으로 설정해 중첩된 Event가 발생했을 때 Element로부터 window까지 이벤트를 전파할지, 혹은 캡쳐링으로 설정해 window부터 Element까지 전파할지 설정할 수 있다.

onClick 메소드는 첫 번째 이벤트를 두 번째 이벤트가 overwrite 되어 첫 번째 이벤트가 구현되지 못하게 한다. 하지만 AddEventListener는 두 이벤트가 전부 구현된다.

useEffect와의 관계

컴포넌트가 렌더링될 때 useEffect 안에서 이벤트 리스너를 등록한다고 했을 때, 이벤트 핸들러가 상태를 사용하고 있는데, 상태가 변경되더라도 핸들러는 업데이트되지 않고 처음에 등록된 핸들러만 계속 작동한다. 그에 대한 예시 코드가 다음과 같다.

const [count, setCount] = useState(0);

const increment = () => setCount(count + 1);

useEffect(() => {
    const handleClick = () => {
      console.log('Current count:', count); // 여기에 상태를 콘솔에 출력
    };

    document.getElementById('myButton').addEventListener('click', handleClick);

    return () => {
      document.getElementById('myButton').removeEventListener('click', handleClick);
    };
}, []); // 의존성 배열이 비어 있어서 처음 렌더링 때만 실행됨

useEffect의 의존성 배열이 비어 있어서, 이벤트 핸들러는 컴포넌트가 처음 렌더링될 때만 설정된다. 이때 핸들러는 상태가 0일 때의 값을 기억한다. Increment Count 버튼을 클릭하여 상태를 1, 2, 3 등으로 변경해도, 핸들러가 업데이트되지 않기 때문에 핸들러는 상태 0만 출력한다.

이를 해결하기 위해 의존성 배열에 상태를 추가해줄 수도 있고, useRef를 사용할 수도 있다.

useRef: 상태가 자주 변경될 때 핸들러에서 최신 상태를 계속 참조해야 하는 경우 유용. 상태의 변화를 핸들러에서 직접 반영할 수 있음.
useEffect의 의존성 배열: 상태 변경 시마다 핸들러를 새로 설정하여 최신 상태를 사용. 핸들러가 상태에 의존적일 때 유용하며, 상태 변경에 따라 핸들러를 자동으로 업데이트한다.

useRef를 사용해서 코드를 구현하면 다음과 같이 수정이 가능하다.

  const [count, setCount] = useState(0); // 상태 초기값은 0

  // 상태 값을 최신으로 유지하기 위한 ref
  const countRef = useRef(count);

  // 상태가 변경될 때 ref를 업데이트
  useEffect(() => {
    countRef.current = count;
  }, [count]);

  const handleClick = () => {
    console.log('Current count:', countRef.current);
  };

  useEffect(() => {
    document.getElementById('myButton').addEventListener('click', handleClick);

    return () => {
      document.getElementById('myButton').removeEventListener('click', handleClick);
    };
  }, []); // 의존성 배열이 비어 있어서 처음 렌더링 때만 실행됨

의존성 배열을 추가해주면 다음과 같다.

useEffect(() => {
  const handleClick = () => {
    console.log(count);
  };

  document.getElementById('myButton').addEventListener('click', handleClick);

  return () => {
    document.getElementById('myButton').removeEventListener('click', handleClick);
  };
}, [count]); // 상태가 변경될 때마다 useEffect가 실행됨

참고 자료

Onclick vs AddEventListener 어떤 것을 사용해야 할까?
Web: Event와 addEventListner 알아보기 (개념, React에서 주의할 점)

profile
Frontend🍓

0개의 댓글