예제코드
코드
class useOutsideClick {
ref = null;
onClickOutside = null;
constructor(ref, onClickOutside) {
this.ref = ref;
this.onClickOutside = onClickOutside;
document.addEventListener('mouseup', this.handleClickOutside);
}
handleClickOutside = (event) => {
if (this.ref && !this.ref?.contains?.(event.target)) {
this.onClickOutside(this);
}
}
removeClickListener = () => {
document.removeEventListener('mouseup', this.handleClickOutside);
}
}
초기에는 특정 요소와 외부 영역을 클릭했을 때 실행할 callback 함수가 필요로 합니다.
Node.contains() 메서드는 노드 자체, 직계 자식(childrens) 중 하나이거나, 자식의 직계 자식 등의 여부를 판단해 줍니다. 즉 클릭한 타깃이 초기에 지정한 요소가 맞는지를 판단해 주는 코드입니다.
만약 ref 요소와 일치하지 않으면, 외부 요소를 클릭했다 판단하고 callback을 호출해 줍니다.
const $aside = document.querySelector('aside');
const outsideClick = new useOutsideClick($aside, () => {
console.log('Click!');
});
이제 useOutsideClick 클래스를 인스턴스화시켜 주고, 요소와 클릭 콜백 함수를 지정해 줍니다.
[React] custom hook
const useOutsideClick = ({ onClickOutside }) => {
const ref = useRef(null);
const handleClickOutside = useCallback(
(event) => {
const inside = ref.current?.contains?.(event.target);
if (ref.current && !inside) {
onClickOutside();
}
},
[onClickOutside, ref]
);
useEffect(() => {
document.addEventListener("mouseup", handleClickOutside);
return () => {
document.removeEventListener("mouseup", handleClickOutside);
};
}, [handleClick]);
return ref;
};
위 코드를 React 코드에 맞게 변형시킨 코드입니다. ref.current에 요소를 지정해 주면 요소 외부 영역을 클릭을 감지하고, 콜백 함수를 호출합니다.
const App = () => {
const outsideRef = useOutsideClick(() => console.log('Click!'));
return <div>
<div ref={outsideRef}></div>
</div>;
};
이제 useOutsideClick()으로 외부 영역 클릭을 감지할 수 있게 됩니다.
참고자료
https://developer.mozilla.org/en-US/docs/Web/API/Node/contains