TIL

6월 26일 TIL 리액트로 모달창 만들기

양죠니 2023. 6. 26. 22:21

1. 버튼을 누르면 모달창이 열리고, 모달창 안의 닫기 버튼을 눌러야 닫히는 모달창 만들기

 

  const [isOpen, setIsOpen] = useState(false);

모달의 상태를 boolean값으로 관리할 state를 만들어주고 

 

<button style={onClick={openModal}>
	버튼 1
</button>

모달창을 열 버튼 하나를 만들어준디.

  const openModal = () => {
    setIsOpen(true);
  };

그리고 해당 버튼이 눌렀을때 모달을 열어주는 openModal함수를 onClick으로 지정해준다.

openModal 메서드를 통해 버튼이 눌리면 state 값이 false에서 true로 변경된다. 

 

<div onClick={openModal}>
        버튼 1
</div>
      {
        //isOpen이 true일때만 활성화되게
        isOpen && (
          <div>
            <div>
              <p>
                닫기 버튼을 누르면 닫히는 모달창
              </p>
              <button onClick={closeModal}> 닫기</button>
              <button>확인</button>
            </div>
          </div>
        )
      }

모달의 상태를 의미하는 isOpen state 값이 true이면 모달창이 열리는 위 html 코드를 넣어주면 된다. 

 

이제 모달이 화면 한가운데 뜨게 하는 스타일링을 주어야한다.

styled component 패키지를 다운받고 import까지 한 다음

 

const OuterBox = styled.div` //모달창을 감싸는 젤 바깥쪽 div
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-color: rgba(0, 0, 0, 0.5); 
  display: flex;
  align-items: center;
  justify-content: center;
`;

const InnerBox = styled.div` //모달창을 감싸는 젤 안쪽 div
  background-color: #fff; 
  padding: 20px;
  width: 70%;
  height: 50%;
  border-radius: 12px;
`;

const StBtn = styled.button` //그냥 버튼 스타일링
  border: none;
  cursor: pointer;
  border-radius: 8px;
  background-color: rgb(177, 226, 147);
  color: rgb(0, 0, 0);
  height: 40px;
  width: 100px;
  margin-right: 10px;
`;

바깥쪽 div의 위치를 뷰포트 기준으로 꽉차게 만들어놓고, flex 속성을 통해서 내부 모달 div가 뷰포트 기준으로 한가운데 정렬하게 만든다. 

내부 div는 넓이가 뷰포트의 70%, 높이가 50%인 모달창을 그리게 된다. 

 

  return (
    <div>
      <StBtn onClick={openModal}>
        버튼 1
      </StBtn>
      {
        //isOpen이 true일때만 활성화되게
        isOpen && (
          <OuterBox>
            <InnerBox>
              <p>
                닫기와 확인 버튼 2개가 있고, 외부 영역을 눌러도 모달이 닫히지
                않아요
              </p>
              <StBtn onClick={closeModal}> 닫기</StBtn>
              <StBtn>확인</StBtn>
            </InnerBox>
          </OuterBox>
        )
      }
    </div>
  );

적용하면 이렇게 되고, 

모달창의 닫기버튼을 누르면 isOpen state가 false로 변경하게 되어 모달창이 닫히게 만드는 함수를 onClick으로 넣어주면 된다.

  const closeModal = () => {
    setIsOpen(false);
  };

 

 

 


 

 

 

2. 버튼을 누르면 모달창이 열리고, 모달창 안의 닫기 버튼이나 모달창 외부영역을 누르면 닫히는 모달창 만들기

 

우선 모달창 외부의 영역을 useRef를 이용해서 모달창이 열렸을때 모달창 전체의 영역을 ref로 잡아놓는다 

const modalRef = useRef();
  
return (
    <div>
      <StBtn onClick={openModal}>버튼</StBtn>
      {
        //isOpen이 true일때만 활성화되게
        isOpen && (
          <OuterBox ref={modalRef}>  //여기!
            <InnerBox>
              <p>
                닫기와 확인 버튼 2개가 있고, 외부 영역을 눌러도 모달이 닫히지
                않아요
              </p>
              <StBtn onClick={closeModal}> 닫기</StBtn>
              <StBtn>확인</StBtn>
            </InnerBox>
          </OuterBox>
        )
      }
    </div>
  );

 

useEffect 훅을 사용하여 렌더링이 됐을때 이벤트 리스너를 더해준다

  useEffect(() => {
  // 마우스가 해당 영역을 눌렀을때 clickOutside 메서드가 실행되게함
    document.addEventListener("mousedown", clickOutside);
    return () => {
    	// 컴포넌트가 없어질때 해당 이벤트를 없애줌
      document.removeEventListener("mousedown", clickOutside);
    }; 
  }, []);
  const clickOutside = (event) => {
    if (modalRef.current === event.target) {
      closeModal();
    }
  };

아까 지정한 modalRef의 영역 (모달창 외부의 불투명한 부분)과 클릭한 부분(event.target)이 같다면 closeModal 메서드를 실행시켜 모달창을 닫히게 한다