특정 요소 바깥을 클릭할 경우 이벤트 처리

2021년 11월 03일
제목이 다소 난잡할 수 있으나, 나의 어휘력으로는 이게 한계였던 것 같다.
Modal 혹은 Overlay, Custom Select를 만들게 되었을 때 종종 그 요소가 아닌 배경을 클릭하거나 다른 Element를 클릭하게 되면 해당 요소를 숨기는 등의 이벤트를 주어야할 경우가 생기게 된다.
 
사내에서 맡게 된 투표/설문 에디터의 Select 컴포넌트
사내에서 맡게 된 투표/설문 에디터의 Select 컴포넌트
 
단순히 구현만을 생각하면 document에 event를 걸어 해당 요소가 아니라면 callback을 실행하게끔 만들면 되겠지만,
필요한 컴포넌트마다 이러한 이벤트를 작성하기가 번거롭다.
 
/** 이해를 돕기 위한 예시입니다. */ export const Overlay = props => { // ... const onClickAway = () => ... // 필요한 경우 매번 이렇게 useEffect를 달아주기는 귀찮다. useEffect(() => { document.addEventListener('click', onClickAway); return () => { document.removeEventListener('click', onClickAway); } }, []); return ( <div> // ... </div> ); }
 
그래서 해당 ref 이외의 요소를 클릭하면 callback이 실행되는 간단한 훅을 작성할 수 있다.
 
// src/hooks/index.ts import { RefObject, useEffect } from 'react'; export const useClickAway = (target: RefObject<any>, callback: () => void) => { const handleClickAway = (event: any) => { if (target.current && !target.current.contains(event.target)) { callback(); } }; useEffect(() => { document.addEventListener('click', handleClickAway); return () => { document.removeEventListener('click', handleClickAway); }; }, []); };
import { useRef } from 'react'; import { useClickAway } from './src/hooks'; export const Overlay = props => { const ref = useRef(); useClickAway(ref, () => { // ref 이외의 요소를 클릭했을 때 실행되는 액션 }); return ( <div ref={ref}> // ... </div> ); }