-
[React] 이중모달 구현하기React 2022. 12. 29. 23:07
이중모달을 구현했던 과정을 정리해보겠습니다.
먼저, 제가 구현하고자 했던 이중 모달의 형태는 아래 그림과 같이 모달 형식의 글 상세 페이지 내에서 댓글을 추가하거나, 수정하거나, 삭제하기 위한 드롭다운 디자인의 이중 모달입니다.
댓글 추가, 수정, 삭제를 위한 이중 모달(드롭다운 디자인) 실제 구현 화면 이중 모달이 닫힌 상태에서 위쪽의 점 버튼을 누르면 이중 모달이 열리고, 이중 모달이 열린 상태에서 점 버튼을 다시 누르거나 이중 모달 외부의 영역을 클릭했을 때 이중 모달이 닫히는 기능을 구현하고자 했습니다.
구현은 점 영역 이외의 문서 전체 영역에서 click 이벤트가 발생했을 때 addEventListener로 이중 모달이 닫히는 함수를 호출하는 방식으로 진행하였고, 상세 코드는 아래와 같습니다.
// useDropDown.tsx function useDropDown() { const [isDrop, setIsDrop] = useState(false); const ref = React.useRef<HTMLDivElement>(null); // 이중 모달을 바깥쪽 클릭 시 이중 모달을 닫는 함수 // event가 발생했을 때 event의 target이 ref.current를 포함하는지 확인함 const handleClickOutside = (e: MouseEvent) => { if (ref.current && !ref.current.contains(e.target as Node)) { setIsDrop(false); } }; // 이중 모달 open 상태를 변경하는 함수 const handleChangeDrop = (value?: boolean) => { if (value) { setIsDrop(value); return; } setIsDrop((pre) => !pre); }; // useEffect hook을 사용하여 화면 전체에 click 이벤트가 발생할 때 handleClickOutside 함수 실행 useEffect(() => { document.addEventListener("click", handleClickOutside); return () => { document.removeEventListener("click", handleClickOutside); }; }, []); return { isDrop, ref, handleChangeDrop, }; } export default useDropDown;
// Comment.tsx const Comment = ({ data }: CommentProps) => { const { isDrop, ref, handleChangeDrop } = useDropDown(); return ( <CommentContainer> <CreateInfo> {isDrop && <CommentDropDown />} // isDrop이 true일때 이중 모달 open <div className="info"> <ProfileImg /> <div className="author">{data.nickName}</div> <AuthorOccupationTag occupation={data.occupation} /> <div className="created-at">{data.createdAt}</div> </div> // 점 영역을 ref로 설정, 점 외부의 영역 클릭 시 handleClickOutside 함수 동작 <div ref={ref}> <Image src={ThreeDots} alt="edit" onClick={() => { handleChangeDrop(!isDrop); }} /> </div> </CreateInfo> <p>{data.content}</p> </CommentContainer> ); };
다만, 위와 같이 코드를 작성하게 되면, 이중 모달을 클릭했을 때에도 이중 모달이 닫히는 문제가 발생했습니다.
때문에 console.log로 이중 모달을 클릭했을 때 동작하는 함수를 확인해보았고, 아래와 같이 이중 모달 영역을 클릭했을 때 handleClickOutside 함수가 함께 실행되는 것을 확인할 수 있었습니다.
이는 이중 모달 영역을 클릭했을 때 이중 모달의 상위 요소인 글 상세 페이지 모달 영역에도 이벤트가 전달되는 이벤트 버블링 때문임을 확인하였고, 아래와 같이 이중 모달의 Container 영역에 event.stopPropagation() 메서드를 추가하여 해결할 수 있었습니다.
const CommentDropDown = () => { return ( <Container onClick={(e) => { e.stopPropagation(); }} > // 모달 내용 코드 </Container> ); }; export default CommentDropDown;
'React' 카테고리의 다른 글
[React] React Router <NavLink>를 활용한 탭 메뉴 구현하기 (0) 2023.01.04 [React] debouncing 기법을 활용한 검색 기능 구현 (0) 2022.12.20 [React] 모달 구현 및 모달 오픈 시 외부(배경) 스크롤 막기 (0) 2022.12.16 [React] styled-components를 활용한 재사용 컴포넌트 만들기(with. TypeScript) (0) 2022.09.30