728x90
반응형
1. 개선 전
▶ 로그인 모달이 뜨고 나서 다른 페이지에 가더라도 모달이 사라지지 않음
2. 개선 후
▶ 모달 On인 경우 background 포함 모든 공간 disabled 시키기
3. 포인트
▶ 컴포넌트 1개에서 8가지의 공용모달 팝업을 사용함
=> 리코일로 상태 관리 + 8개의 default 객체로 여러개의 모달 열려있는지 여부 확인
🖥️ 코드
//modal.ts
import { atom } from 'recoil';
import { MODAL_STATE } from './keys';
const modalState = atom({
key: MODAL_STATE.IS_MODAL_OPEN,
default: {
isModalOpen01: false,
isModalOpen02: false,
isModalOpen03: false,
isModalOpen04: false,
isModalOpen05: false,
isModalOpen06: false,
isModalOpen07: false,
isModalOpen08: false,
isModalOpen09: false
}
});
export { modalState };
▶ 리코일로 상태 관리 + 8개의 default 객체로 여러개의 모달 열려있는지 여부 확인
//Layout.tsx
import { PropsWithChildren } from 'react';
import styled from 'styled-components';
import Footer from './footer/Footer';
import NavBar from './navbar/NavBar';
import { useRecoilValue } from 'recoil';
import { modalState } from '../recoil/modals';
function Layout({ children }: PropsWithChildren) {
const {
isModalOpen01,
isModalOpen02,
isModalOpen03,
isModalOpen04,
isModalOpen05,
isModalOpen06,
isModalOpen07,
isModalOpen08,
isModalOpen09
} = useRecoilValue(modalState);
return (
<LayoutContainer
$isModalOpen={
isModalOpen01 ||
isModalOpen02 ||
isModalOpen03 ||
isModalOpen04 ||
isModalOpen05 ||
isModalOpen06 ||
isModalOpen07 ||
isModalOpen08 ||
isModalOpen09
}
>
<div>
<NavBar />
<MainWrapper>{children}</MainWrapper>
</div>
<Footer />
</LayoutContainer>
);
}
export default Layout;
type LayoutProps = {
$isModalOpen: boolean;
};
const LayoutContainer = styled.div<LayoutProps>`
display: flex;
flex-direction: column;
justify-content: space-between;
background-color: ${(props) => (props.$isModalOpen ? 'rgba(0, 0, 0, 0.02)' : 'white')};
backdrop-filter: ${(props) => (props.$isModalOpen ? 'saturate(180%) blur(8px)' : 'none')};
// overflow: ${(props) => (props.$isModalOpen ? 'hidden' : 'unset')};
`;
const MainWrapper = styled.div`
display: flex;
flex-direction: column;
align-items: center;
margin: 60px auto 0 auto;
`;
▶ props로 모달창 열린 여부 (true/false) 확인 후,
styled-components를 삼항연산자로 표시
function Signup() {
const modal = useModal();
const [isModalOpen, setIsModalOpen] = useRecoilState(modalState);
const emailCheck = async (email: string) => {
const userRef = collection(db, 'users');
const q = query(userRef, where('userEmail', '==', email));
const querySnapshot = await getDocs(q);
if (querySnapshot.docs.length > 0) {
const onClickSave = () => {
setIsModalOpen((prev) => ({ ...prev, isModalOpen03: false }));
modal.close();
};
const openModalParams: Parameters<typeof modal.open>[0] = {
title: '이미 존재하는 이메일입니다.',
message: '',
leftButtonLabel: '',
onClickLeftButton: undefined,
rightButtonLabel: '확인',
onClickRightButton: onClickSave
};
modal.open(openModalParams);
setIsModalOpen((prev) => ({ ...prev, isModalOpen03: true }));
setIsFormValid(false);
setIsChecked(false);
setValue('email', email);
return;
} else if (email === '') {
const onClickSave = () => {
setIsModalOpen((prev) => ({ ...prev, isModalOpen04: false }));
modal.close();
};
const openModalParams: Parameters<typeof modal.open>[0] = {
title: '이메일을 입력해주세요.',
message: '',
leftButtonLabel: '',
onClickLeftButton: undefined,
rightButtonLabel: '확인',
onClickRightButton: onClickSave
};
modal.open(openModalParams);
setIsModalOpen((prev) => ({ ...prev, isModalOpen04: true }));
return;
}
};
▶ 해당 컴포넌트에서 8개의 공용모달창을 사용해서,
isModalOpen01~ isModalOpen08로 사용
=> isModalOpen01 한가지로 8개의 공용모달창의 상태를 관리하는 것은
리액트 라이프사이클에 맞지 않다고 생각했음
끝.
반응형
'TIL :: Today I Learned' 카테고리의 다른 글
useEffect의 dependency array에서 무한루프 (0) | 2024.02.06 |
---|---|
데이터 수정/삭제시 쿼리키 invalidateQueries (0) | 2024.01.31 |
리액트 + 파이어베이스 + 알고리아 = 검색 기능 구현 (1) | 2024.01.29 |
1차 유저 피드백 (1) | 2024.01.29 |
리액트 prefetch 테스트 : prefetchInfiniteQuery 적용하기 (1) | 2024.01.25 |