-
Notifications
You must be signed in to change notification settings - Fork 7
베이스 모달 만들기
데스크탑 앱인 디스코드를 클로닝한 덕스코드 프로젝트의 특성상
메인 레이아웃 위에서 일어나는 동작들(채팅, 화상채팅 등) 외의 동작들(채널 추가/삭제 등)은
로그인/회원가입 기능을 제외하면 모두 모달에서 동작됩니다.
모달이 많이 사용되는 만큼, 재사용 가능하고 다른 팀원들이 쉽게 사용할 수 있는 베이스 모달 컴포넌트를 구현해두기로 결정했습니다.
https://github.com/boostcampwm-2021/web09-Duxcord/pull/100
모달의 디자인을 분석하며 위의 그림과 같이 공통적인 부분들을 찾을 수 있습니다.
- 제목
- 부연 설명
- 우측 상단 닫기 버튼
- 좌측 하단 뒤로 가기 버튼
- 우측 하단 버튼
그리고 몸통 부분은 다른 컴포넌트로 끼워주기로 결정하였습니다.
또한 각 버튼이 수행하는 동작은 달라질 수 있으니
모달의 상태를 제어하는 함수들을 모은 ModalController
라는 인터페이스를 따로 정의해 모달의 prop으로 받도록 하였고,
우측 하단의 버튼이 수행하는 동작과 색상은 ModalButton
인터페이스 형태로 받아오도록 하였습니다.
interface ModalData {
title?: string;
subTitle?: string;
middleContent: ReactElement<any, any>;
bottomRightButton?: ModalButton | null;
}
interface ModalController {
hide: function;
show?: function;
previous?: function;
next?: function;
}
interface ModalButton {
text: string;
onClickHandler: function;
color: string;
}
모달을 닫을 때 애니메이션을 주기 위하여 3초의 interval을 추가적으로 주어 hide 함수를 덮어썼습니다.
isHidden
속성을 Background
와 Wrapper
모두에게 주어 사라질 때의 애니메이션을 서로 다르게 주었습니다.
좌측 하단 버튼이 '이전'일 경우와 '닫기'일 경우가 있어 상황에 맞게 렌더링되도록 코드를 짜두었습니다.
그 외의 속성들은 모두 위의 디자인과 알맞게 배치했습니다.
function Modal({
props: { title, subTitle, middleContent, bottomRightButton },
controller: { hide, previous },
}: {
props: ModalData;
controller: ModalController;
}) {
const [hidden, setHidden] = useState(false);
const hideModal = () => {
setHidden(() => true);
setTimeout(() => {
hide();
}, 300);
};
return (
<Background onClick={hideModal} isHidden={hidden}>
<Wrapper onClick={(e) => e.stopPropagation()} isHidden={hidden}>
<Top>
<ModalCloseIcon onClick={hideModal} />
</Top>
{title && <Title>{title}</Title>}
{subTitle && <SubTitle>{subTitle}</SubTitle>}
<div>{middleContent}</div>
{bottomRightButton && (
<Bottom>
{previous ? (
<BottomLeftButton onClick={previous}>이전</BottomLeftButton>
) : (
<BottomLeftButton onClick={hideModal}>닫기</BottomLeftButton>
)}
<BottomRightButton
color={bottomRightButton.color}
onClick={bottomRightButton.onClickHandler}
>
{bottomRightButton.text}
</BottomRightButton>
</Bottom>
)}
</Wrapper>
</Background>
);
}
function GroupJoinModal({ controller }: { controller: ModalController }) {
const InputComponent = (
<Input
onChange={(e) => updateGroupCode(e.target.value)}
placeholder='그룹 코드를 입력해주세요'
/>
);
return
(<Modal
props={{
title: '그룹 참가하기',
subTitle: '아래에 초대 코드를 입력해 그룹에 참가하세요',
middleContent: InputComponent,
bottomRightButton: {
title: '그룹 참가하기',
color: colors.Blue,
onClickHandler: joinGroup,
},
}}
controller={controller}
/>);
위의 베이스 모달 덕분에 정말 많은 모달 컴포넌트가 수월하게 생성될 수 있었습니다.