모달창 오픈시 이외에 부분 작동 안 하게 처리 (리코일 사용)

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개의 공용모달창의 상태를 관리하는 것은

리액트 라이프사이클에 맞지 않다고 생각했음

 

 

 

 

끝.

반응형