일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- leetcode문제풀이
- JS
- CSS
- react
- 자바스크립트 알고리즘
- Next.js13
- Next
- HTML
- 프로그래머스
- 알고리즘문제풀이
- 리액트쿼리
- JavaScript
- next13
- 리액트
- 자바스크립트 문제 풀이
- 프론트엔드
- 자바스크립트 연결리스트
- 제로베이스
- 자바스크립트
- lodash
- 자바스크립트 문제
- 자바스크립트 알고리즘 문제
- NPM
- 타입스크립트
- stack문제
- 자바스크립트코딩테스트
- 자바스크립트 문제풀이
- Baekjoon
- leetcode
- til
- Today
- Total
코드노트
리액트 createPortal로 DOM추가하기 본문
ReactDOM.createPortal(child, container)
- createPortal은 리액트에서 DOM트리 <div id="root"> 의 다른 위치에 컴포넌트를 렌더링을 할 수 있는 기능
- 기본적으로 컴포넌트는 컴포넌트 트리의 노드로 렌더링이 되지만, 컴포넌트를 루트 DOM요소 밖의 다른 위치에 렌더링해야 할때 사용할 수 있다.
- 간단하게 말하면 첫번째 인자는 자식요소, 두번째 인자는 자식요소를 렌더링할 DOM요소
ex) 모달, 툴팁, 독립적인 컴포넌트 등등
이번 프로젝트에서 모달을 사용하면서 css를 사용하여 z-index를 조절하여 모달을 만들었는데
createPortal을 사용하는것이 좋다고 한다. 아니 맞는것 같다.
- 모달은 기존 컴포넌트 구조와 격리되어야한다.
- 컴포넌트와 상호작용하는 문제가 발생할 수 있다.
이 외에도 kakaomap API를 테스트 하면서 map 안에서 표시되는 마커를 생성할 때에도 createPortal을 사용했었다.
그때도 지도에 따로 접근하고 그 접근한 마커를 동적으로 제어할때 문제가 생겨서
독립적으로 생성하고 표시하였는데 모달에도 적용하고 코드를 수정하는게 맞는것 같다.
사용방법
<html lang="en" className={openSans.className}>
<body>
<div id="portal" />
</body>
</html>
- getElementById를 사용하여 DOM을 추가할 것이기 때문에 id를 가진 div요소를 추가한다.
// ModalPoralComponent.tsx
import { useEffect } from "react";
import reactDom from "react-dom";
type Props = {
children: React.ReactNode;
};
export default function ModalPortal({ children }: Props) {
const el = document.getElementById("portal") as Element;
return reactDom.createPortal(children, el);
}
- 이렇게 컴포넌트로 만들어서 사용하면 재사용에 있어서도 좋은것 같다.
- 모달로 사용할 컴포넌트를 이제 ModalPortal의 children으로 넣어주면 쉽게 사용할 수 있다.
- 여기서 만난 문제 모달을 사용하게 되면 만약 스크롤이 있다면 모달 뒤에 화면에서도 스크롤이 진행된다.
- 모달을 가장 위로 보여주고 뒤에 있는 스크롤을 막고 싶다면 window에서 제어할 요소를 찾아서 style을 조절해주자.
useEffect(() => {
const originalStyle = window.getComputedStyle(document.body).overflow;
document.body.style.overflow = "hidden";
return () => {
document.body.style.overflow = originalStyle;
};
}, []);
if (typeof window === "undefined") {
return null;
}
- useEffect를 사용하여 마운트되면 getComputedStyle 메서드를 사용하여 overflow 스타일 속성을 hidden으로 설정하여 스크롤을 막아줄 수 있다.
스크롤 방지 적용 코드
import { useEffect } from "react";
import reactDom from "react-dom";
type Props = {
children: React.ReactNode;
};
export default function ModalPortal({ children }: Props) {
useEffect(() => {
const originalStyle = window.getComputedStyle(document.body).overflow;
document.body.style.overflow = "hidden";
return () => {
document.body.style.overflow = originalStyle;
};
}, []);
if (typeof window === "undefined") {
return null;
}
const el = document.getElementById("portal") as Element;
return reactDom.createPortal(children, el);
}
createPortal을 사용하는 경우는 생각보다 많이 있는것 같다.
DOM을 직접적으로 따로 생성하는 작업들은 많이 하지 않았었는데
모달, 팝업, 알림창과 같은 독립적으로 사용되는 컴포넌트를 만들때 편하게 사용할 수 있다.
컴포넌트 재사용 뿐만 아니라 다른 코드에서도 활용할 수 있는곳에서 활용을 할 수 있도록 해봐야겠다.
'Code note > 리액트' 카테고리의 다른 글
리액트쿼리를 쓴다면 이건 꼭 알고 쓰자 (0) | 2024.03.20 |
---|---|
리액트 가상돔 Virtual DOM 정리 (0) | 2023.08.04 |
Redux의 구조 정리, feat. Flux 패턴 (0) | 2023.07.24 |
리액트(컴포넌트) 에러처리 ErrorBoundary ... class... (1) | 2023.04.12 |
REACT Hooks 노트 React.memo (feat.useMemo, useCallback) (0) | 2023.04.02 |