React, Next, Redux/🚀 React with Hooks
custom hook (1) : Detect click outside of DOM
DarrenKwonDev
2021. 1. 21. 03:02
아래와 같은 notification(혹은 dropdown)은 다른 곳을 눌렀을 때 해당 dom을 지워줘야 한다.
당연히 구현 자체는 클릭하면 showPopUp이란 state가 true/false로 토글되면서 해당 dom을 보여주냐, 마느냐가 결정됩니다.
<MenuRightButton onClick={handleClickNotice} ref={NotificationDom}>
<i className="fas fa-bell" aria-hidden></i>
<span>Notice ({popUpNumber})</span>
{showPopUp && <NoticePopUpComponent showPopUp={showPopUp} setshowPopUp={setshowPopUp} />}
</MenuRightButton>
문제는 완전 다른 곳을 클릭했을 때입니다. 이 경우 상식적으로 해당 드랍 다운을 꺼줘야 하는데 이를 어떻게 감지할까요?
아래와 같이 해주면 됩니다. 설명은 주석으로 달았습니다.
간단히 요약하자면, 화면 전체에 event를 걸어놓고서, 클릭 이벤트가 발생한 곳의 dom이 지정한 dom이 아니면 로직을 발동시키는 것입니다.
import { useEffect } from 'react';
function useDetectOutsideClick(ref) {
useEffect(() => {
function handleClickOutside(event) {
// mousedown 이벤트가 발생한 ref의 값이 지정한 dom에 해당하는지 체킹합니다.
if (ref.current && !ref.current.contains(event.target)) {
// useRef를 달아준 dom이 아닌 다른 곳을 클릭하면 alert이 실행됩니다.
alert('You clicked outside of me!');
}
}
// document(화면 전체)에 eventListener를 달아줍니다.
document.addEventListener('mousedown', handleClickOutside);
return () => {
// useEffect이므로 remove하여 momory leak을 방지합니다.
document.removeEventListener('mousedown', handleClickOutside);
};
}, [ref]);
}
export default useDetectOutsideClick;
저는 setState를 담아서 외부를 클릭하면 state를 false로 설정하도록 만들어주었습니다.
function useDetectOutsideClick(ref, setState) {
useEffect(() => {
function handleClickOutside(event) {
if (ref.current && !ref.current.contains(event.target)) {
// dom 바깥 클릭
setState(false);
}
}
document.addEventListener('mousedown', handleClickOutside);
return () => {
document.removeEventListener('mousedown', handleClickOutside);
};
}, [ref]);
}
참고)
stackoverflow.com/questions/32553158/detect-click-outside-react-component
www.cluemediator.com/detect-click-outside-a-react-component-using-react-hooks