์ฑ์ ๋ค์ํ ํ์ด์ง์์ ๋ชจ๋ฌ์ ์ฌ์ฉํ๋ค. ๊ทธ๋ฆฌ๊ณ ๋ฏธ๋ฆฌ ์ง์ ๋์ง ์์ ์ค๋ฅ์ ๋ํด์๋ ์บ์นํด์ ๋ชจ๋ฌ์ ๋์ฐ๋๋ก ๋์ด์๋ค. ๊ทธ๋ ๊ธฐ ๋๋ฌธ์ ๋ชจ๋ฌ์ ์ ์ญ์ผ๋ก ๊ด๋ฆฌํด์ ์ฌ์ฉํด๋ณด๊ธฐ๋ก. ๋ฑ ํค์ฆ์ ๋น์ทํ๊ฒ ์ฌ์ฉํ์ง๋ง ์กฐ๊ธ์ ๋ค๋ฅธ ๋ฐฉ์์ด๋ค. ์ฐธ๊ณ
6๊ฐ์ ์ , 1์ฐจ ํ๋ก์ ํธ ์ค์ ์งฐ๋ ์ฝ๋์ด๋ค.
import React from 'react';
const ModalComponent = ({ children }, ref) => {
return (
<div className="modal hidden" ref={ref}>
<div
className="modal-overlay"
onClick={() => {
ref.current.classList.add('hidden');
}}
></div>
<div className="modal-content">{children}</div>
</div>
);
};
export default React.forwardRef(ModalComponent);
์ด๋ ๊ฒ ๋ชจ๋ฌ ์ปดํฌ๋ํธ๋ฅผ ๋ง๋ค์ด๋๊ณ ,
function TicketCodePage({ ...props }) {
const modalRef = useRef();
const onClick={() => {
modalRef.current.classList.remove('hidden');
}}
// ...
return (
<TicketWrapContainer>
// ...
<ModalComponent ref={modalRef}>
<ModalBox
onClickClose={() => {
modalRef.current.classList.add('hidden');
}}
/>
</ModalComponent>
</TicketWrapContainer>
);
}
export default TicketCodePage;
๋ชจ๋ฌ์ด ํ์ํ ํ์ด์ง๋ง๋ค ๋ชจ๋ฌ ์ปดํฌ๋ํธ๋ฅผ ๋ฌ์์ค๋ค. ref
๋ก div์์๋ฅผ ๊ฐ์ ธ์์ ์ง์ class๋ฅผ ๋ฐ๊ฟ๊ฐ๋ฉฐ display ์์ฑ์ ๋ฐ๊ฟ์ฃผ๋ ํ์์ด์๋ค. ๋ฌด์๋ณด๋ค ์ด๊ฒ ์ ์ผ ๋ง์ ์๋ค์์. ๋ ๋ชจ๋ฌ์ ์ฌ์ฉํ๋ ํ์
๋ง๋ค ๋๊ฐ์ ์ฝ๋๋ฅผ ์ฌ๋ฌ๋ฒ ์์ฑํด์ผ ํ๋๋ฐ, ์ด ๋ถ๋ถ๋ ์ง์ ๋ ํ์
์ผ๋ก ๊ด๋ฆฌ๋ฅผ ํ๊ณ ์ถ์๋ค. ๋ค์๊ณผ ๊ฐ์ ํ์
๋ค์ด ์๋ค.
- ์์ํก์ ๋จ๊ธฐ๊ธฐ ์ ์ด๋ฆ๊ณผ ๋ด์ฉ์ ํ์ธํ๊ณ ์ ์ก
- ์์ผ ์๋ต์ ๋ฐ๊ณ ๋ ํ ์๋ฌ ์ฒ๋ฆฌ
- API ์์ฒญ์ ์๋ต์ ๋ฐ๊ณ ๋ ํ ์๋ฌ ์ฒ๋ฆฌ
- ๊ณต์ฐ์ฅ ์ ๋ณด, ๊ฐ๋ฐ์ ์๊ฐ ๋ฑ์ ๋ณ๋ ํ์ด์ง๋ก ๋นผ์ง ์๋ ์ ๋ณด
๋ชจ๋ฌ์ ์ ์ญ์ผ๋ก ๊ด๋ฆฌํ๋ฉด ๊ฐ ์ปดํฌ๋ํธ์์ ๋งค๋ฒ ๋ชจ๋ฌ์ ์ํฌํธํด์ ๋ฃ์ด์ค ํ์๊ฐ ์์ด์ง๋ค.
GlobalModal.tsx
export const MODAL_TYPES = {
Notice: 'Notice',
CheckBeforeSend: 'CheckBeforeSend',
Location: 'Location',
Developers: 'Developers',
} as const;
const ModalComponents: any = {
[MODAL_TYPES.Notice]: Notice,
[MODAL_TYPES.CheckBeforeSend]: CheckBeforeSend,
[MODAL_TYPES.Location]: Location,
[MODAL_TYPES.Developers]: Developers,
};
const GlobalModal = () => {
const [modal, setModal] = useRecoilState(modalState);
const { modalType, modalProps } = modal || {};
const renderComponent = () => {
if (!modalType) {
return null;
}
const ModalComponent = ModalComponents[modalType];
return (
<Modal>
<Overlay onClick={() => setModal(null)} />
<Container>
<ModalComponent {...modalProps} />
</Container>
</Modal>
);
};
return <>{renderComponent()}</>;
};
export default GlobalModal;
๋จผ์ GlobalModal
์ปดํฌ๋ํธ๋ฅผ ๋ง๋ค์ด ์ต์์(๋ด ๊ฒฝ์ฐ์ index.tsx)์ ๋ฃ์ด๋๋ค. styled-component
๋ฅผ ์ฌ์ฉํ ์ฝ๋์ด๋ค. ์ค์ํ๊ฒ ๋ด์ผํ ๊ณณ์ ๋ฆฌ์ฝ์ผ์ ๋ชจ๋ฌ ์ํ๋ฅผ ์ ์ฅํ๋ ๊ฒ๊ณผ, GobalModal์์ ๋ณด์ฌ์ค ๋ชจ๋ฌ์ ์ข
๋ฅ๋ค์ ์ฝ๋์ ๊ฐ์ด ModalTypes ๊ฐ์ฒด๋ก ๊ด๋ฆฌํ๋ ๊ฒ - ๋ ๊ตฐ๋ฐ์ด๋ค. ModalTypes ์์๋ ๊ฐ ๋ชจ๋ฌ์ ํ์
์ ๋ฌธ์์ด๋ก ๊ฐ๊ณ ์๋ค๊ฐ ModalCompoents์์ ๊ฐ ํ์
์ ๊ฐ์ ํค๋ก ํ๋ ๊ฐ์ฒด๋ก ๋ชจ๋ฌ ์ปดํฌ๋ํธ ์์ฒด๋ฅผ ๊ด๋ฆฌํ๋ค. ๋ฆฌ์ฝ์ผ ์ํ์ ์ ์ฅํด๋ ๊ฐ์ด ์์ ๋ ํด๋น ๋ชจ๋ฌ์ ๋ ๋๋งํ๊ณ , ์ํ๋ฅผ null๋ก ๋ฐ๊พธ๋ฉด renderComponent()
์์ null
์ ๋ฆฌํดํ๋ฏ๋ก ์๋ฌด๊ฒ๋ ๋ ๋๋งํ์ง ์๋๋ค!
stores/modal.ts
import { atom } from 'recoil';
import { MODAL_TYPES } from '../components/modal/GlobalModal';
export type TNoticeModal = {
modalType: typeof MODAL_TYPES.Notice;
modalProps: any;
};
export type TCheckBeforeSendModal = {
modalType: typeof MODAL_TYPES.CheckBeforeSend;
modalProps: any;
};
export type TLocationModal = {
modalType: typeof MODAL_TYPES.Location;
modalProps: any;
};
export type TDevelopersModal = {
modalType: typeof MODAL_TYPES.Developers;
modalProps: any;
};
export type ModalType =
| TNoticeModal
| TCheckBeforeSendModal
| TLocationModal
| TDevelopersModal;
export const modalState = atom<ModalType | null>({
key: 'modalState',
default: null,
});
ModalState์๋ ๋๊ฐ์ง ์ ๋ณด๊ฐ ๋ค์ด๊ฐ๋ค. ์ด๋ค ์ข
๋ฅ์ ๋ชจ๋ฌ์ด ๋ค์ด๊ฐ์ง, ๊ทธ๋ฆฌ๊ณ ํด๋น ๋ชจ๋ฌ ์ปดํฌ๋ํธ์ ๋ค์ด๊ฐ props. ์ปดํฌ๋ํธ ์์ฒด๋ฅผ ๋ฐ๋ก ์ฐ์ง ์๊ณ MODAL_TYPES
๋ฅผ ์ค๊ฐ์ ๋์ด ๋ ๋๋งํ๋๋ฐ์ ์ด์ ๊ฐ ์ฌ๊ธฐ์ ์๋ค. ๋ฆฌ์ฝ์ผ ์ํ์๋ JSX ์์๋ฅผ ๋ด์ ์ ์๋ค. ๋ฑ
ํค์ฆ์์ ์ฌ์ฉํ๋ ๋ฆฌ๋์ค๋ ๋๊ฐ์ ์ด์ ๋๋ฌธ์ ๋ฐ๋ก context api๋ฅผ ์ฌ์ฉํ๋๋ฐ, ์ด ๋ฐฉ๋ฒ์ ์ฌ์ฉํ๋ฉด ๋์๋ค!!
useModal.tsx
const useModal = () => {
const [modal, setModal] = useRecoilState(modalState);
const openModal = ({ modalType, modalProps }: ModalType) => {
setModal({ modalType, modalProps });
};
const closeModal = () => {
setModal(null);
};
return { openModal, closeModal };
};
export default useModal;
๋ชจ๋ฌ์ ์ด๊ณ ๋ซ๋ ํจ์๋ฅผ ์ปค์คํ ํ ์ ํตํด ์ถ์ํํด์ ์ฐ๊ณ ์๋ค.
openModal({
modalType: 'CheckBeforeSend',
modalProps: {
onClick: () => {
mutate({ nickName, content });
closeModal();
console.log('asdf');
},
closeModal,
content,
nickName,
},
});
๋ชจ๋ฌ์ด ํ์ํ ๊ณณ์์ ์ด๋ ๊ฒ openModal ํจ์๋ฅผ ์ธ ์ ์๋ค.