목표 : 홈페이지에서 다양하게 사용되는 모달을재사용성과, 확장성이 높은 모달을 만들어보고자 함.
public / -index.tsx
<body>
<div id="root"></div>
<div id="modal-root"></div>
</body>
부모 컴포넌트의 DOM 계층 구조 바깥에 있는 DOM 노드로 자식을 렌더링하는 방법
: createPortal을 사용하여 해당 컴포넌트의 HTML 내용을 다른 곳으로 포털, 즉 이동시킬 수 있다!
components/modal/ModalPortal.ts
import ReactDom from 'react-dom';
import { ReactNode } from 'react';
type ModalPortalProps = {
children: ReactNode;
};
const ModalPortal = ({ children }: ModalPortalProps) => {
const modalRoot = document.getElementById('modal-root') as HTMLElement;
return ReactDom.createPortal(children, modalRoot);
};
export default ModalPortal;
import * as S from './Modal.styled';
import React from 'react';
import ModalPortal from './ModalPortal';
export type ModalProps = {
children: React.ReactNode;
isOpen: boolean;
closeModal: () => void;
};
const Modal = ({ children, isOpen, closeModal }: ModalProps) => {
const handleClose = (e: React.MouseEvent<HTMLElement>) => {
e.stopPropagation();
closeModal();
};
return <ModalPortal>{isOpen ? <S.Overlay onClick={handleClose}>{children}</S.Overlay> : null}</ModalPortal>;
};
export default Modal;
import { useState } from 'react';
import { Modal, ModalProps } from '../components';
type UseModalReutnType = {
Modal: React.FC<ModalProps>;
isOpen: boolean;
openModal: () => void;
closeModal: () => void;
};
const useModal = (): UseModalReutnType => {
const [isOpen, setIsOpen] = useState(false);
const openModal = () => setIsOpen(true);
const closeModal = () => setIsOpen(false);
return {
Modal,
isOpen,
openModal,
closeModal,
};
};
export default useModal;
import * as S from './Dialog.styled';
type DialogProps = {
closeModal: () => void;
};
const Dialog = ({ closeModal }: DialogProps) => {
return (
<S.Container>
<S.Inner
onClick={(e: React.MouseEvent<HTMLElement>) => {
e.stopPropagation();
}}
>
<button onClick={closeModal}>닫기</button>
</S.Inner>
</S.Container>
);
};
export default Dialog;
import React from 'react';
import { useModal } from '../hooks';
import { Dialog } from '../components';
const Main = () => {
const { Modal, isOpen, openModal, closeModal } = useModal();
return (
<>
<Modal isOpen={isOpen} closeModal={closeModal}>
<Dialog closeModal={closeModal} />
</Modal>
<button onClick={openModal}>열기</button>
</>
);
};
export default Main;
생각이 필요한 부분 :
1. Dialog의 디자인에 맞춰서 어떻게 children 값을 보여주면 좋을지 고민해보기
2. 타입을 잘 지정해주고 있는지 확인해보기
최고에요