728x90
React 로 개발하던 중, 특정 영역 밖을 클릭하면 떠있던 모달이 내려가거나 상태를 바꿔줘야 하는 경우가 발생했습니다.
이 때 물론 useState를 사용하거나 useRef를 사용해 바로 구현해도 되지만 hook으로 빼면 코드가 좀 더 간결해질 수 있습니다.
//useClickOutside.ts
import { useEffect, MutableRefObject } from 'react';
function useClickOutside<T extends HTMLElement>(ref: MutableRefObject<T | null>, onClickOutside: () => void) {
useEffect(() => {
/**
* Invoke Function onClick outside of element
*/
function handleClickOutside(event: MouseEvent) {
if (ref.current && !ref.current.contains(event.target as Node)) {
onClickOutside();
}
}
// Bind
document.addEventListener('click', handleClickOutside);
return () => {
// dispose
document.removeEventListener('click', handleClickOutside);
};
}, [ref, onClickOutside]);
}
export default useClickOutside;
//Component.tsx
import useClickOutside from 'hooks/useClickOutside';
import { useRef, useState } from 'react';
export default function Component() {
const [showModal, setShowModal] = useState(false);
const compRef = useRef<HTMLInputElement>(null);
useClickOutside(compRef, () => {
setShowModal(false);
});
return <div ref={compRef}>...</div>;
}
위처럼 사용할 수 있습니다.
만약 클릭이 허용되는 (눌러도 상태가 변하지 않아야 하는) 영역이 많다면 ref 를 배열로 받도록 수정해야 합니다.
import { useEffect, MutableRefObject } from 'react';
function useClickOutside<T extends HTMLElement>(refs: Array<MutableRefObject<T | null>>, onClickOutside: () => void) {
useEffect(() => {
/**
* Invoke Function onClick outside of element
*/
function handleClickOutside(event: MouseEvent) {
let refNotClickedCnt = 0;
for (const ref of refs) {
if (ref.current && !ref.current.contains(event.target as Node)) {
refNotClickedCnt += 1;
}
}
if (refNotClickedCnt === refs.length) {
onClickOutside();
}
}
// Bind
document.addEventListener('click', handleClickOutside);
return () => {
// dispose
document.removeEventListener('click', handleClickOutside);
};
}, [refs, onClickOutside]);
}
export default useClickOutside;
import useClickOutside from 'hooks/useClickOutside';
import { useRef, useState } from 'react';
export default function Component() {
const [showModal, setShowModal] = useState(false);
const compRef = useRef<HTMLInputElement>(null);
const inputRef = useRef<HTMLInputElement>(null);
useClickOutside([compRef, inputRef], () => {
setShowModal(false);
});
return (
<div>
<div ref={compRef}>{}</div>
<input ref={inputRef}>{}</input>;
</div>
);
}
'코드 기록' 카테고리의 다른 글
[flask-cors] 재설치 (0) | 2024.08.24 |
---|---|
개발자 도구 방지 코드 우회하기 (0) | 2024.08.06 |
[Pyqt5] QMainWindow 배경 이미지 설정하기 (0) | 2024.04.14 |
Why & What (is) Spidergen ? (0) | 2024.03.30 |
Restudy Series. Javascript (2) (0) | 2024.03.30 |