@cp949/mui
Version:
CP949 MUI React component library
87 lines (83 loc) • 2.51 kB
text/typescript
import { useEffect, useRef } from 'react';
/**
* HTML 요소에 이벤트 리스너를 안전하게 추가하고 관리하는 React 훅입니다.
* 컴포넌트가 언마운트될 때 자동으로 이벤트 리스너를 제거하여 메모리 누수를 방지합니다.
*
* @template K - HTML 요소 이벤트 맵의 키 타입
* @template T - 타겟 HTML 요소의 타입
* @param type - 듣고자 하는 이벤트 타입 (click, mouseover, keydown 등)
* @param listener - 이벤트가 발생했을 때 호출될 콜백 함수
* @param options - addEventListener의 옵션 (capture, once, passive 등)
* @returns 이벤트를 듣고자 하는 요소에 연결할 ref 객체
*
* @example
* ```tsx
* const Component = () => {
* const buttonRef = useEventListener(
* 'click',
* (event) => {
* console.log('버튼 클릭!', event.target);
* }
* );
*
* return (
* <button ref={buttonRef}>
* 클릭 이벤트가 자동으로 바인딩됨
* </button>
* );
* };
* ```
*
* @example
* ```tsx
* // 다양한 이벤트 옵션 사용
* const Component = () => {
* const divRef = useEventListener(
* 'wheel',
* (event) => {
* event.preventDefault();
* console.log('휠 이벤트 발생');
* },
* { passive: false, capture: true }
* );
*
* return (
* <div ref={divRef} style={{ height: 200, overflow: 'auto' }}>
* 스크롤 방지 영역
* </div>
* );
* };
* ```
*
* @example
* ```tsx
* // 타입 안전성을 위해 구체적인 요소 타입 지정
* const Component = () => {
* const inputRef = useEventListener<'focus', HTMLInputElement>(
* 'focus',
* (event) => {
* console.log('입력 필드 포커스');
* event.target.select(); // HTMLInputElement의 select 메서드 사용 가능
* }
* );
*
* return <input ref={inputRef} type="text" />;
* };
* ```
*/
export function useEventListener<K extends keyof HTMLElementEventMap, T extends HTMLElement = any>(
type: K,
listener: (this: HTMLDivElement, ev: HTMLElementEventMap[K]) => any,
options?: boolean | AddEventListenerOptions,
) {
const ref = useRef<T | undefined>(undefined);
useEffect(() => {
const element = ref.current;
if (element) {
element.addEventListener(type, listener as any, options);
return () => element.removeEventListener(type, listener as any, options);
}
return undefined;
}, [type, listener, options]);
return ref;
}