배경
모달 또는 팝업창을 닫을 때 외부 영역 클릭 이벤트를 감지해야 하는데, 그 때마다 아래와 같은 코드를 작성해야 한다. 똑같은 코드를 매번 작성하는 것은 정말 번거로운 일이다. 그래서 커스텀 훅으로 분리하여 재사용한다.
const containerRef = useRef(null);
useEffect(() => {
function handleClickOutside(e) {
if (containerRef.current && !containerRef.current.contains(e.target)) {
setIsBankListOpen(false);
}
}
document.addEventListener('mousedown', handleClickOutside);
return () => {
document.removeEventListener('mousedown', handleClickOutside);
};
}, []);
useOnClickOutside
import { RefObject, useEffect } from 'react';
export default function useOnClickOutside<T extends HTMLElement>(
ref: RefObject<T | null>,
handler: (event: MouseEvent | TouchEvent) => void,
) {
useEffect(() => {
const listener = (event: MouseEvent | TouchEvent) => {
// ref.current가 없거나, 클릭한 대상이 ref 내부에 있다면 아무 작업도 수행하지 않음
if (!ref.current || ref.current.contains(event.target as Node)) {
return;
}
handler(event);
};
// mousedown, touchstart 이벤트를 감지
document.addEventListener('mousedown', listener);
document.addEventListener('touchstart', listener);
// 컴포넌트 unmount 시 이벤트 리스너 제거
return () => {
document.removeEventListener('mousedown', listener);
document.removeEventListener('touchstart', listener);
};
}, [ref, handler]);
}
'IT > Front-End' 카테고리의 다른 글
프론트엔드 서비스 최적화? 토스에서는 이렇게 합니다! - 정리 (1) | 2025.03.09 |
---|---|
[FE] 번들 다이어트에 대한 타사 사례 조사 (0) | 2025.03.01 |
[FE] flex 팀의 마이크로 프론트엔드 전환기 - 정리 (0) | 2025.03.01 |
[FE] 섬세한 ISFP의 코드 가독성 개선 경험 - 정리 (1) | 2025.02.24 |
[FE] eslint & prettier에서 Biome으로 마이그레이션하기 (0) | 2025.02.18 |