드롭다운을 visible한 element와 드롭다운 컨텐츠를 제외한 곳을 클릭할시에 없어져야한다.
위에 조건때문에 드롭다운을 만드는게 까다롭긴하다 때문에 다음과같이 웹퍼를 만들어 사용하자.
import { uniqueId } from 'lodash-es';
import React, { useEffect, useRef, type PropsWithChildren } from 'react';
import type { CSSProperties } from 'styled-components';
interface DropDownWrapperProps {
setIsVisible: React.Dispatch<React.SetStateAction<boolean>>;
css?: CSSProperties;
isOpen: boolean;
}
const DropDownWrapper = ({
setIsVisible,
children,
css,
isOpen,
}: PropsWithChildren<DropDownWrapperProps>) => {
const modalWrapperRef = useRef<HTMLDivElement>(null);
useEffect(() => {
const outSideClick = (e: MouseEvent) => {
// 2. 클릭한위치가 웹퍼 밖인지를 contains으로 확인한다.
if (
modalWrapperRef.current &&
!modalWrapperRef.current.contains(e.target as Node)
) {
setTimeout(() => {
setIsVisible(false);
}, 0);
}
};
// 1. 도큐멘트에서 클릭이밴트가 발생할시에
if (isOpen) {
window.addEventListener('click', outSideClick, true);
} else {
window.removeEventListener('click', outSideClick, true);
}
return () => {
window.removeEventListener('click', outSideClick, true);
};
}, [setIsVisible, isOpen]);
if (isOpen) {
return (
<div style={css} id={uniqueId()} ref={modalWrapperRef}>
{children}
</div>
);
} else {
return null;
}
};
export default DropDownWrapper;
차일드 외에 클릭이 일어날경우 드롭다운을 invisible한다.