댓글마다 개별 모달 렌더링하기
댓글마다 개별 모달 렌더링하기
이번에 댓글 기능을 구현하면서 댓글에 있는 점 옵션 메뉴를 클릭하면 수정,삭제 모달이 뜨도록 구현했는데, 문제는 옵션 버튼을 클릭하면 전체 댓글의 모달이 뜨는 문제가 생겼다. 이때까지 로그인 모달 등 모달이 하나만 뜨면 되는 것을 구현했었는데, 이번에는 어떻게 클릭한 리뷰를 특정해서 모달을 열리게 할까 고민해보았다.
원래코드는 점 버튼을 클릭했을 때 isOptionMenuOpen을 true로, 리뷰 전체 컨테이너를 클릭하면 false로 프롭스를 이용해서 렌더링을 관리했었다.
export const StOptionsMenuModal = styled.ul`
z-index: 999;
width: 65px;
height: 65px;
font-size: 12px;
display: ${(props) => (props.$isOptionMenuOpen ? 'flex' : 'none')};
그러다 보니 전체 리뷰 컴포넌트의 display 속성을 한번에 제어하게 된 것이다.
해결한 방법은 이러하다.
리뷰아이디를 저장할 state를 만들고 점 옵션버튼을 클릭했을 때 state를 클릭한 리뷰 아이디로 set해준다.
// 클릭한 리뷰 아이디를 저장할 state 선언
const [clickedReviewId, setClickedReviewId] = useState(null);
// 점 메뉴를 클릭 시 클릭한 리뷰 아이디로 setState
<StHiOutlineDotsVertical onClick={() => handleOptionButtonClick(item.id)} />
const handleOptionButtonClick = (id) => {
setClickedReviewId(id);
};
// map 함수 return 부분
{clickedReviewId === item.id && (
<StOptionsMenuModal>
//중략
</StOptionsMenuModal>
)}
그런다음 클릭한 리뷰아이디와 item의 id가 같으면 모달이 열리게 조건부렌더링한다.
즉 점점점을 클릭하면 clickedReviewId가 클릭한 리뷰의 아이디가 되고, item.id는 원래 댓글이 가지고있던 아이디니까
둘이 일치할때만 모달을 보여주도록 조건을 걸어주면 해결할 수 있었다.
모달 바깥 영역을 클릭했을 때 닫히게 하기
다른 곳을 클릭했을 떄 닫히도록 하는건 모달창에 ref를 걸어서 구현했다.
이해하는게 조금 어려웠는데, 옵션버튼을 클릭하지 않았을때 modalRef의 값은 null이다. 옵션버튼을 클릭하면 모달이 열리면서 DOM node가 생기고, 따라서 modalRef의 참조값이 생겨 null이 아니게 된다. 이 상태에서 모달을 닫는 이벤트 함수를 걸어준 영역을 클릭하면 handleModalClose 함수가 호출되면서 modalRef.current가 null이 아닌지 확인하게 되고, 모달이 열려있는 상태에선 modalRef.current가 null이 아니므로 if값은 true, 클릭한 리뷰아이디를 다시 null로 set해서 모달이 닫히게 된다.
옵션버튼은 handleModalClose 이벤트 함수가 걸려있는 컨테이너 안에 있기 때문에, if 조건을 걸어주지 않으면 클릭했을 때 handleModalClose의 setClickedReviewId(null)이 실행되어 모달이 열리지 않는다.
const handleModalClose = () => {
if (modalRef.current) setClickedReviewId(null);
};