모달을 처음 만들어 보기도 하고 타입스크립트도 처음 다루어서 정말 어려웠다....
오늘 완성은 하지 못했지만 React의 Portal이라는 기능을 이용해 fullPage 모달에 사용할 모달을 만들었다.
React Portal이란?
부모 컴포넌트의 DOM 계층 구조의 밖에 있는 DOM노드로 자식(children)을
렌더링하는 방법을 제공할 수 있게 해주는 친구
ReactDOM.createPortal(child, container)
위와같이 사용해주면 되는데,
child에 포탈을 통해 밖으로 보낼 대상이 되는 컴포넌트,
container는 포탈을 통해 child가 이동할 곳
한마디로 child를 렌더링할 DOM Element를 넣어준다는 것이다.
Portal을 통해 모달을 만들려면 모달 컴포넌트가 렌더링 될 DOM Element를 index.html에 추가해줘야한다.
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="modal"></div>
<div id="root"></div>
</body>
아래는 내가 만든 모달의 구조이다.
// ModalPortal (모듈화를 위해 만들어줌)
import { createPortal } from 'react-dom';
interface Props {
children?: React.ReactNode
}
const Modal: React.FC<Props> = ({ children }) => {
return (
createPortal(<>{children}</>, document.getElementById("modal") as HTMLElement)
)
};
export default Modal;
위의 코드는 모달이 열리고 닫히는 동작을 할 수 있게 해주는 props를 전달할
컴포넌트들에 사용하기 위해 모듈화를 목적으로 작성되었다.
위의 코드를 사용하면 아래와 같은 모습이다.
// Header.tsx
...
const Header = ({ authorized }: User) => {
const [modalIsOpen, setModalOpen] = useState(false);
const onClickButton = () => {
setModalOpen(!modalIsOpen);
};
return (
<div className="header">
<Link to="/">
<GamaldaIcon width='70px' height='70px'/>
</Link>
<div className="login_link">
{authorized ?
<div>
<UserIcon width='50px' height='50px' onClick={onClickButton} />
{modalIsOpen && <AccountInfoModal onClose={() => setModalOpen(false)} />}
</div>
:
...
결과적으로 전달되는 모달 컴포넌트는 아래와 같다.
// AccountInfoModal.tsx
import ModalPortal from 'components/modules/Modal/ModalPortal'
// onClose의 타입은 테스트가 끝나면 알맞는 바꾸도록하자
const AccountInfoModal = ({ onClose }: any) => {
return (
<ModalPortal>
<div className="modal_info_box">
<h3>test</h3>
<button type="button" onClick={onClose}>닫기</button>
</div>
</ModalPortal>
)
}
export default AccountInfoModal;
Header.tsx에서 onClose를 모달 상태를 반전해주는 함수로 받았다.
받은 onClose를 버튼의 onClick에 할당해주며 닫히는 기능을 추가했다.
위의 과정은 결과적으로 팀원과 코드리뷰를 통해 다른 모달을 구현할 때 사용하기로 했다.
이유는 리액트는 부모 컴포넌트에서 자식 컴포넌트로 정보가 전달되는 구조인데
자식 컴포넌트를 부모 DOM 외부에 보내게 된다면 정보 전달의 문제가 있지 않을까라는 것이다.
글을 쓰던 도중 Portal에 대한 글을 찾았다.
이 글에서는 부모 컴포넌트에서 자식 컴포넌트로 전파되는 이벤트 등이나
자식 컴포넌트에서 부모 컴포넌트로 전달되는 이벤트(이벤트 버블링 같은) 등이 제대로 전달된다고 한다.
이는 DOM 트리에서 해당 위치에 어떤 자식 컴포넌트가 있는지 확인할 수 있지만,
React 트리에서는 자식 컴포넌트가 잇어야 하는 기존 위치에 Portal이 있다는 것을 확인할 수 있다
이벤트 버블링 또한 DOM트리 내 상위 컴포넌트가 아니라 React 트리의 Portal의 상위 컴포넌트로 전달된다.
글의 출처 : https://medium.com/hcleedev/web-react-portal-%EC%95%8C%EC%95%84%EB%B3%B4%EA%B8%B0-f00a48157862
오늘은 Portal을 이용해 모달을 만들어봤다.
일단 내일은 알바 퇴근 뒤 모달을 다시 만들어 볼 생각이다.
헤더에 들어가기에 우선 ref와 reletive, absolut를 이용해 만들어 볼 생각이며,
된다면 hook을 만들어서 모달을 적용할 생각이다.
또한 오늘 만든 Portal을 이용한 모달은 모듈화를 위해 개조를 할 생각이다.
(시간이 난다면..... 목요일에 이어서 할 예정이다)
'프로젝트 > 가말다 - 마일스톤' 카테고리의 다른 글
로그아웃 기능 중 쿠키 전달을 위한 fetch의 credentials(내용증명) 옵션 사용 (0) | 2023.04.19 |
---|---|
BE - DB연결 방식 변경 (Prisma -> SQL쿼리) (0) | 2023.04.06 |
모달 제작 -2 (0) | 2023.02.03 |
상단 헤더 제작 (0) | 2023.01.29 |
프로젝트 소개 (0) | 2023.01.24 |