본문으로 건너뛰기

useEventListener

useEventListener는 지정한 이벤트 타입에 대해 타겟 요소에 안전하게 이벤트 리스너를 등록·해제하는 커스텀 React 훅입니다.

DOM 요소, window, document, MediaQueryList 등 다양한 이벤트 타겟에 대응하며, 최신 콜백 유지와 자동 정리까지 처리합니다.

🔗 사용법

useEventListener(target, type, listener, options);

매개변수

이름타입설명
targetRefObject<EventTarget> | EventTarget이벤트를 등록할 대상 (ref 객체 또는 직접 지정 가능)
typestring이벤트 타입 (예: 'click', 'resize', 'keydown')
listener(e: Event) => void이벤트 발생 시 실행될 콜백 함수
optionsboolean | AddEventListenerOptions (선택)이벤트 등록 옵션 (capture, once, passive 등)

✅ 예시

1. window 리사이즈 이벤트

import React, { useState } from 'react';
import { useEventListener } from './useEventListener';

function WindowSizeLogger() {
const [size, setSize] = useState({ width: window.innerWidth, height: window.innerHeight });

useEventListener(window, 'resize', () => {
setSize({ width: window.innerWidth, height: window.innerHeight });
});

return (
<div>
<p>가로: {size.width}px</p>
<p>세로: {size.height}px</p>
</div>
);
}

2. 특정 DOM 요소 클릭 감지

import React, { useRef, useState } from 'react';
import { useEventListener } from './useEventListener';

function ClickCounter() {
const buttonRef = useRef<HTMLButtonElement>(null);
const [count, setCount] = useState(0);

useEventListener(buttonRef, 'click', () => {
setCount((prev) => prev + 1);
});

return (
<div>
<button ref={buttonRef}>클릭 횟수: {count}</button>
</div>
);
}

3. MediaQueryList 이벤트 감지

import React, { useState } from 'react';
import { useEventListener } from './useEventListener';

function DarkModeDetector() {
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
const [isDark, setIsDark] = useState(mediaQuery.matches);

useEventListener(mediaQuery, 'change', (e: MediaQueryListEvent) => {
setIsDark(e.matches);
});

return <div>현재 모드: {isDark ? '다크 모드' : '라이트 모드'}</div>;
}

📋 주의사항

  • listener 함수는 내부에서 최신 참조를 유지하므로, 매 렌더마다 이벤트를 재등록할 필요가 없습니다.
  • options 객체를 매번 새로 만들면 재등록이 발생하므로, 필요한 경우 useMemo로 안정화하는 것이 좋습니다.
  • target이 null인 경우(예: 조건부 렌더링 시), 이벤트는 등록되지 않습니다.
  • cleanup은 훅 내부에서 자동으로 처리되므로 별도 해제가 필요 없습니다.
  • ref 객체를 사용할 때는 ref.current가 유효한 시점에만 이벤트가 등록됩니다.