
React Portal
리액트 포탈 논리적으로는 하위 컴포넌트여야 하는데, 시각적으로는 상위 컴포넌트를 덮어야 할 상황일 때 사용하는 기능입니다. 리액트 v16에서 도입된 기능으로, 기존의 리액트에서 컴포넌트를 렌더링하게 될 때 children은 부모 컴포넌트의 DOM 내부에 렌더링되어야 하지만, Portal…
2021. 05. 24읽기 1분335자
리액트 포탈
논리적으로는 하위 컴포넌트여야 하는데, 시각적으로는 상위 컴포넌트를 덮어야 할 상황일 때 사용하는 기능입니다.
리액트 v16에서 도입된 기능으로, 기존의 리액트에서 컴포넌트를 렌더링하게 될 때 children은 부모 컴포넌트의 DOM 내부에 렌더링되어야 하지만, Portals를 사용하면 DOM의 계층 구조 시스템에 종속되지 않으면서 컴포넌트를 렌더링할 수 있습니다. 따라서 모달창과 같은 다이얼로그 컴포넌트를 리액트 포탈을 이용해 개선할 수 있습니다.
PortalContainer 구현
// Portal Component
import React, { useState, useRef, useEffect } from 'react'
import { createPortal } from 'react-dom'
interface IPortalProps {
children: React.ReactNode
selector: string
}
export const PortalContainer: React.FC<IPortalProps> = ({ children, selector }) => {
const ref = useRef<any>()
const [mounted, setMounted] = useState(false)
useEffect(() => {
ref.current = document.querySelector(selector)
setMounted(true)
}, [selector])
return mounted ? createPortal(children, ref.current) : null
}모달 컴포넌트 구현 (모달 레이아웃)
// Modal Component
import React, { Dispatch, SetStateAction } from 'react'
import styles from './Modal.module.scss'
import classNames from 'classnames/bind'
import { PortalContainer } from '../../../containers/commons/PortalContainer'
const cx = classNames.bind(styles)
export interface IModalProps {
setModalVisible: Dispatch<SetStateAction<boolean>>
onSubmitHandler: (e: React.MouseEvent) => void
visible: boolean
children?: React.ReactNode
}
const Modal: React.FC<IModalProps> = ({ setModalVisible, onSubmitHandler, visible, children }) => {
return (
<PortalContainer selector="body">
<div className={cx(`modal ${visible && 'visible'}`)}>
<div className={cx('modal-content')}>
<h1 className={cx('title')}>모달 확인</h1>
<div className={cx('content')}>{children}</div>
<div className={cx('button-container')}>
<button className={cx('cancel-btn')} onClick={() => setModalVisible(false)}>
취소하기
</button>
<button className={cx('ok-btn')} onClick={onSubmitHandler}>
확인하기
</button>
</div>
</div>
<div className={cx('modal-bg')} onClick={() => setModalVisible(false)}></div>
</div>
</PortalContainer>
)
}
export default Modal테스트 모달 구현
import React from 'react'
import { Modal } from '../Modal'
import { IModalProps } from '../Modal/Modal'
import styles from './TestModal.scss'
import classNames from 'classnames/bind'
const cx = classNames.bind(styles)
type IProps = IModalProps
const TestModal: React.FC<IProps> = ({ visible, setModalVisible, onSubmitHandler }) => {
return (
<>
<button className={cx('modal-btn button')} onClick={() => setModalVisible(true)}>
Modal Test
</button>
{visible && (
<Modal
visible={visible}
setModalVisible={setModalVisible}
onSubmitHandler={onSubmitHandler}
>
콘텐츠
</Modal>
)}
</>
)
}
export default TestModal→ 버튼 컴포넌트가 렌더링되고, 클릭 시 모달 컴포넌트가 body 태그 아래에 렌더링됩니다.
테스트 화면

→ 앱 안에 있는 'Modal Test' 버튼을 이용하여 앱 밖으로 모달창을 조작할 수 있게 되었습니다.
같은 카테고리의 글 · React
ReactReact Test 코드 작성💡 개요 모든 개발자들이 테스트 코드 작성의 중요성에 대해서 알지만, 쉽사리 실무에서 테스트 코드를 작성하면서 개발하기란 쉬운 일이 아니라는 것에 공감하실 것입니다. 특히나 프론트엔드에서는 시각적인 부분이 많다 보니 아무래도 눈으로 직접 검증하는 경우가 많은데요. 테스트 코드를 통해…
ReactReact 상태관리💡 등장배경 초기 웹을 돌아보면 Back-end 서버로부터 웹페이지를 동적으로 렌더링해주어 Front-end에서의 상태관리는 물론 별도의 Front-end 서버도 필요하지 않았습니다. 하지만 점차 서버의 부하를 줄이고 사용자들에게 원활한 서비스를 제공하기 위해 페이지 렌더링과 UI 작…