모달창 밑에 있는 외부 컨텐츠들(예시코드에서 mainContent)은 가리고
(스타일상으로 가리는것뿐만 아니라 접근성 측면에서도 외부 컨텐츠들과 분리하려면)
<div class="mainContent">
...
</div>
<Modal>
</Modal>
이런식으로 마크업이 되어야할텐데,
메인컨텐츠 내부 컴포넌트 어딘가에서 버튼을 클릭할때마다
Modal창을 제대로 위치시키려면 어떻게 해야할지 고민이였다.
이전에는 Modal의 마크업 위치를 고정시켜두고,
간단한 알림내용만 보여주는 경우에는 몇개의 고정된 데이터(open, title, content, button)들을
redux-toolkit을 사용해서 알림창을 필요로하는 컴포넌트에서 상태변경만 해줬다.
그런데,
모달창안에 title, content, button뿐만 아니라 input이나 다양한 요소들을 넣고 싶을땐
모달이라는 컴포넌트를 만들어두고, children으로 내부를 좀더 자유롭게 쓰면 좋겠는데
그러면 모달창은 마크업상 위치를 최상단에 두려면 어떻게 해야하나 방법을 찾게 되었다.
: 일부 자식을 DOM의 다른 부분으로 렌더링할 수 있게 해줌 (최상단에 엘리먼트를 위치시킬 수 있음)
포털은 DOM노드의 물리적 배치를 변경하는 것임
<div>
<SomeComponent />
{createPortal(children, domNode, key?)}
</div>
import { createPortal } from "react-dom";
type props = {
id: string,
title: string,
children: React.ReactNode
}
function Modal ({id, title, children}: props) {
return (
<div>
{
createPortal(
<div style={{}}>
<div role="dialog" aria-labelledby={`label_${id}`} aria-modal="true">
<h2 id={`label_${id}`}>{title}</h2>
{children}
</div>
</div>,
document.body
)
}
</div>
)
}
export default Modal
props중 children에 바로 React.ReactNode 타입 지정해줬을때 자꾸 에러가 났다.
function Modal ({children}: React.ReactNode) {
그래서 다른 사람들 코드보고
타입 별칭으로 만들어두고 사용하니 에러가 안났다.
type props = {
children: React.ReactNode
}
function Modal ({children}: props) {
그렇기 때문에 props에 대한 타입은 객체로 지정하고,
children은 React.ReactNode로 타입지정을 아래와 같이 해줘야함.
function Modal({ children }: { children: React.ReactNode }) {}
<button type="button" onClick={() => modal.current.showModal()}>모달열기</button>
<dialog ref={modalRef}>
...
<button type="button" onClick={() => modal.current.close()}>모달닫기</button>
</dialog>
const modalRef = useRef<HTMLDialogElement>(null)
const handleCloseModal = () => {
modalRef.current?.close();
}
const handleFindIdClick = () => {
modalRef.current?.showModal();
};
return (
<>
<div>
<h3>로그인</h3>
<LoginForm />
<button type="button" onClick={handleFindIdClick}>
아이디 찾기
</button>
</div>
<dialog ref={modalRef}>
<input type="text" />
<div>
<button type="button">확인</button>
<button type="button" onClick={handleCloseModal}>닫기</button>
</div>
</dialog>
</>
);
modalRef.current?.close();
wai-modal접근성
React로 모달 구현하기 - CreatePortal과 Dialog 비교
react-ko.dev 비공식 한글 번역 사이트-creatPortal
[TypeScript] 리액트 children 타입 지정해주기 - 타입별 특징
HTML 요소 참고서-dialog
useRef : Object is Possibly null 오류와 관련해서