돔요소의 바깥쪽을 클릭했을때 콜백함수를 실행하게하는 커스텀 훅
import { useEffect, useRef, useCallback } from "react";
type OutsideClickCallback = () => void;
export const useOutsideClick = () => {
// 현재 요소와 콜백을 저장
const elementRef = useRef<HTMLElement | null>(null);
const callbackRef = useRef<OutsideClickCallback>(() => {});
useEffect(() => {
const handleClick = (e: MouseEvent) => {
const element = elementRef.current;
if (!element) return;
if (!element.contains(e.target as Node)) {
callbackRef.current();
}
};
// 모바일도 고려!
document.addEventListener("mousedown", handleClick);
document.addEventListener("touchstart", handleClick, { passive: true });
return () => {
document.removeEventListener("mousedown", handleClick);
document.removeEventListener("touchstart", handleClick);
};
}, []);
// stable한 ref 콜백 - useEvent 패턴 활용
const stableCallback = useCallback((element: HTMLElement | null) => {
elementRef.current = element;
if (!element) return;
// React 19 cleanup 활용!
return () => {
elementRef.current = null;
};
}, []);
// 콜백을 업데이트하고 stable ref를 반환하는 함수
return (callback: OutsideClickCallback) => {
callbackRef.current = callback;
return stableCallback;
};
};
const onOutsideClick = useOutsideClick();
<div ref={onOutsideClick(() => setIsOpen(false))}>메뉴 내용</div>;