React (6) Fragments, Portals

llsh·2022년 4월 11일
0

Fragments, Portals

JSX 제한 사항 및 해결 방법

JSX는 기본적으로 여러 요소들을 같이 사용할 경우 이들을 감싸주는 요소가 필요합니다.

이때 "div" 태그를 사용해서 wrapping 해주면 다음과 같은 문제점이 발생 합니다.

  1. 실제 DOM으로 렌더릴 될때 리액트 컴포넌트가 많이 중첩될 수 있다.
  2. 페이지에 어떤 의미나 구조적인 의미를 가지지 않지만 스타일을 망칠 수도 있다.
  3. 너무 많은 HTML요소를 렌더링 하기 때문에 애플리케이션이 느려질 수도 있다.

그래서 이를 위한 해결 방법으로는 다음과 같은 방법들이 있습니다.

<> </> 빈 태그 사용하기

장점으로는 짧고 간편합니다, 그리고 실제 HTML요소를 DOM에 렌더링하지 않는다.
하지만 프로젝트 설정에 따라 다르기 때문에 빌드 워크플로가 이를 지원 해야 사용할 수 있다.

	<>
    	<div>HI</div>
        <div>HIII</div>
    </>

Fragment 사용

이것도 마찬가지로 실제 HTML요소를 DOM에 렌더링 하지 않는다.
그리고 리액트에 내장되어 있기 때문에 항상 사용할 수 있다.

사용 방법은 Fragment를 따로 임포트해서 사용하거나 React.Fragment를 사용하면 된다.

	<React.Fragment>
    	<div>HI</div>
        <div>HIII</div>
    </React.Fragment>

Wrapper 컴포넌트 사용

Wrapper 컴포넌트를 따로 만들어서 사용 해도 DOM에 영향을 주지 않는다.
다음과 같이 작성하면 빈껍데기에 하위 요소를 렌더링 해주는거기 때문에 위에 두 방법과 동일하다.

    const Wrapper = props => {
        return {props.children}
    }
    export default Wrapper 

	<Wrapper>
    	<div>HI</div>
        <div>HIII</div>
    </Wrapper>

Portal


이전 포스팅에서 모달을 구현할때 위와 같은 방식으로 구현 하였는데 이때 스타일링을 통해서 동작은 잘하지만 구조적으로 봤을때 문제점이 생긴다.

우선 모달은 오버레이이다.

오버레이는 전체 페이지 위에 표시되는 것을 말하는데 위와 같이 구현 했을때 다른 HTML 코드 안에 중첩 되어 렌더링 되기 때문에 스타일링을 통해 작동은 할지 몰라도 좋은 구조를 가지는 것은 아니다, 그리고 스크린 리더가 HTML 코드를 해석할 때 일반적인 오버레이로 인식하지 못 할 수도 있다.

또한 이것은 HTML 코드 안 깊은 곳에 자리 잡고 있기 때문에 다른 모든 내용에 대한 오버레이인지 명확하지 않다.

이를 위한 해결 방법으로는 리액트의 포털을 사용하면 된다.

Portal 사용법

ReactDOM.createPortal은 렌더링될 HTML 내용을 지정해둔 포인터로 옮겨 주기 때문에 오버레이를 사용할때 사용하면 좋다.

이때 렌더링 되어야 하는 리액트 노드(반드시 JSX),DOM 엘리먼트

1. public 폴더의 index.html(렌더링되는 html파일)에 렌더링 되어야 하는 포인터를 설정 해준다.

<body>
	<div id="backdrop-root"></div>
    <div id="overlay-root"></div>
	<div id="root"></div>
</body>

2. ReactDOM 을 임포트 해준다(설치).

import ReactDom from "react-dom"

3. ReactDOM.createPortal 사용될 컴포넌트 생성

import React from "react";
import ReactDOM from "react-dom";
import Button from "../UI/Button";
import Card from "../UI/Card";

import styles from "./Modal.module.css";

const Backdrop = ({ onCloseModal }) => {
    return <div className={styles.backdrop} onClick={onCloseModal}></div>;
};

const ModalOverlay = ({ onCloseModal, message, title }) => {
    return (
        <Card className={styles.modal}>
            <h2 className={styles.head}>{title}</h2>
            <div className={styles.content}>{message}</div>
            <div className={styles.control}>
                <Button type="button" onClick={onCloseModal}>
                    Okay
                </Button>
            </div>
        </Card>
    );
};

4. ReactDOM.createPortal사용

JSX안에서 사용되기 때문에 {}를 사용해준다.

const ErrorModal = ({ onCloseModal, message, title }) => {
    return (
        <React.Fragment>
            {ReactDOM.createPortal(
                <Backdrop onCloseModal={onCloseModal} />,
                document.getElementById("backdrop-root")
            )}
            {ReactDOM.createPortal(
                <ModalOverlay
                    onCloseModal={onCloseModal}
                    title={title}
                    message={message}
                />,
                document.getElementById("backdrop-root")
            )}
        </React.Fragment>
    );
};
export default ErrorModal;

출처 【글로벌 Best】 React 완벽 가이드 with Redux, Next.js, TypeScript

profile
기록 기록 기록..

0개의 댓글