모달을 조건부 렌더링으로 구현하였지만, 애니메이션 효과가 없어서 UI가 너무 딱딱하게 느껴졌다.
검색해보니 대부분은 opacity: 0 으로 투명하게 만들고 클릭시 1로 바꿔 보이게끔 하는 방법을 사용하는 내용이었는데, 여러 시행착오 끝에 결론은 @keyframes와 animation을 이용하여 애니메이션을 추가하여 문제를 해결했다.
모달창을 구현하기 위해 3가지 조건이 필요했다.
- 모달창이 나타날 때 다른 요소보다 위에 위치하여 렌더링 되어야 했고
- 내부 버튼들도 잘 동작해야 했으며
- 마지막으로 백그라운드를 눌러도 모달창을 닫을 수 있어야 했다.
opacity를 사용하면 문제점
- 모달 백그라운드 뒤의 버튼이나 요소들이 클릭되지 않거나 동작하지 않는 문제가 발생한다.
pointer-events : none
속성을 사용하여 제어할 수 있으나, 백그라운드 클릭으로 닫을수가 없고, 모달창 내부의 버튼 등을 사용할 수 없게 된다. - 브라우저에는 보이지 않지만, 실제로는 렌더링이 되어 있기 때문에 버그와 같은 문제가 발생할 수 있으며, 대규모 웹의 경우 메모리 낭비 문제가 발생할 수 있다.
컴포넌트
모달을 더욱 효율적으로 제어하기 위해 커스텀 훅을 만들어 props 없이도 모달을 제어할 수 있도록 구현하였다.
또한, 모달이 생성 되면 백그라운드와 x 버튼을 누를시 모달이 사라지는 기능을 추가했다.
// Modal.tsx
import React,{ useState } from 'react';
...
const Header = () => {
const { clickHandler } = useModal();
return(
...
// 클릭시 모달 생성
<LoginSection>
<p className="login" onClick={() => clickHandler(true)}>
로그인
</p>
</LoginSection>
);
};
const Modal = () => {
const {isOpen , clickHandler } = useModal();
return (
// isOpen 기준 조건부 렌더링
<Container display={isOpen ? 'flex' : 'none'}>
// 모달 백그라운드 클릭시 isOpen 값이 false로 바뀌는 함수
<ModalBackground onClick={() => clickHandler(false)} />
<ModalWindow>
// x 버튼 클릭시 isOpen 값이 false로 바뀌는 함수
<p className="close" onClick={() => clickHandler(false)}>
×
</p>
</ModalWindow>
</Container>
);
};
// useClick.ts
import { useState } from 'react';
//useModal의 interface
interface ModalHook {
isClick: boolean;
clickHandler: () => void;
}
// 모달을 제어하는 커스텀 훅
const useModal = () : ModalHook => {
const [isOpen, setIsOpen] = useState(false);
// 클릭 시 isOpen의 boolean 값 변경으로 모달을 제어하는 기능
const clickHandler = (isClicked : boolean) => {
setClick(isClicked);
};
return { isOpen, clickHandler }
}
styled-components
백그라운드를 클릭할 때 모달이 사라지는 설정과 애니메이션을 적용하여 부드럽게 모달이 나타나고 사라지도록 설정했다.
// modalstyled.ts;
const Container = styled.div`
display: ${(props) => props.display || 'none'};
justify-content: center;
align-items: center;
background-color: rgb(0, 0, 0, 0.6);
`;
const ModalBackground = styled.div`
position: fixed;
left: 0;
top: 0;
right: 0;
bottom: 0;
`;
// 모달 애니메이션 적용 설정
const ModalWindow = styled.div`
position: relative;
width: 380px;
height: 550px;
background: white;
padding: 0 30px;
animation: modaldown 0.5s linear;
@keyframes modaldown {
from {
transform: translateY(-10%);
}
to {
transform: translateY(0);
}
}
.close {
position: absolute;
right: 15px;
top: 5px;
cursor: pointer;
font-size: 25px;
}
`;
- 위
animation : modaldown 0.5s linear;
속성은animation-name(임의의 이름)
,animation-delay
순 으로 설정한것이다. @keyframes
규칙에서from(애니메이션 시작)
은translateY(-10%)
약간 위로 이동하도록 설정했고,to(종료)
는translateY(0)
원래대로 돌아오도록 설정했다.
원하는 결과물이 나왔다.