Kimsora✨
article thumbnail
Published 2022. 12. 4. 18:36
Fragment/Portal React
320x100
반응형

Fragment

리액트에서는 하나의 컴포넌트가 여러 개의 엘리먼트들을 반환한다. 리액트를 사용하기 위한 문법인 JSX 를 쓸 때, return 문 안에는 반드시 하나의 최상위 태그가 있어야 한다( 리액트가 하나의 컴포넌트만을 리턴할 수 있기 때문)

=> fragment를 사용하면 dom에 별도의 노드를 추가하지 않고 여러자식을 그룹화 할 수 있다.

 

const  Table= ()=> {

    return (
      <table>
        <tr>
          <Columns />
        </tr>
      </table>
    );
  
}

const  Columns  {
    return (
      <div>
        <td>hi</td>
        <td>bye</td>
      </div>
    );

}

Table 컴포넌트가 유효하려면 <Columns />가 여러 <td>엘리먼트를 반환해야 하는데 <Columns />가 <td />를 <div>로 감싸서 반환한다면 실제 dom tree는 아래와 같이 구성된다

<table>
  <tr>
    <div>
      <td>hi</td>
      <td>bye</td>
    </div>
  </tr>
</table>

=>이렇게 구성된 html은 유효하지 않다.

 

Fragment 사용예시

const  Table= ()=> {

    return (
      <table>
        <tr>
          <Columns />
        </tr>
      </table>
    );
  
}

const  Columns  {
    return (
      <React.Fragment>
        <td>hi</td>
        <td>bye</td>
      </React.Fragment>
    );

}
//short syntax  단축문법
const  Columns  {
    return (
      <>
        <td>hi</td>
        <td>bye</td>
      </>
    );

}

key 또는 어트리뷰트를 지원하지 않는다는 것을 빼고 다른 엘리먼트처럼 <></>을 사용할 수 있다

아래와 같이 구성된다

<table>
  <tr>
      <td>Hello</td>
      <td>World</td>
  </tr>
</table>

 

 

=>

  1. Fragment는 불필요한 DOM node의 생성을 막기 때문에 메모리를 적게 사용한다.
  2. css 메커니즘에서 특별한 부모 자식관계를 가지고 있는 flexbox나 grid관계에 있는 엘리먼트 사이에 <div>를 추가하게 되면 레이아웃을 유지하기 어려워지므로 fragment를 사용한다

Portal

부모 컴포넌트의 DOM 계층 구조 바깥에 있는 DOM 노드로 자식을 렌더링하는 방법이다

=>외부에 존재하는 DOM 노드 React App DOM 계층 안에 존재하는 것처럼 연결을 해주는 포탈 기능을 제공

일반적으로 react는 부모 컴포넌트가 렌더링되면 자식 컴포넌트가 렌더링되는 tree 구조를 가지고 있다.

부모-자식 관계를 유지하지만 독립적인 위치에서 렌더링을 하면 훨씬 편리한 경우( 모달이 켜진 상태에서 업데이트 등으로 부모 엘리먼트가 리렌더된다면, tree구조에 따라 자식인 모달 역시 영향을 받게 된다 ,부모 컴포넌트의 스타일링에 제약을 받아 z-index 와 같은 후처리를 해야한다는 점)가 있다.

=>DOM Tree 상에서의 부모-자식 간의 제약에서 자유로워지기 위해 Portal 기능을 사용한다

 Portal에 렌더링된 자식요소는 이벤트 버블링이 반영되기 때문에 부모요소와의 통신 측면에서도 유용하다

 

Portal 사용법

ReactDOM.createPortal(<엘리먼트 />, 배치할 DOM 식별자);

 

1. public/index.html에 Modal이 렌더링 될 위치 심어주기

=> 기존 최상단 요소인 root의 형제관계로 modal 요소를 넣기

  <body>
    <div id="root"></div>
    <div id="modal"></div>
  </body>

 

2. Portal.js 

=>modal div를 가져와 children으로 넣어주는, Portal역할을 할 Portal.js를 만들어준다.

//Portal.js

import reactDom from "react-dom";

const ModalPortal = ({ children }) => {
  const el = document.getElementById("modal");
  return reactDom.createPortal(children, el);
};

export default ModalPortal;

 

3.Modal.js 

=>렌더링시켜줄 modal.js 를 만든다  <Background>는 실제 modal의 뒷배경 부분,modal 창은 <Content> 이다

/Modal.js

import React from "react";
import styled from "styled-components";


const Background = styled.div`
  height: 100%;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  position: fixed;
  left: 0;
  top: 0;
  text-align: center;
`;

const Content = styled.div`
  height: 100%;
  width: 950px;
  margin-top: 70px;
  position: relative;
  overflow: scroll;
  background: #141414;
`;

const Modal = ({onClose}) => {

  return (
      <Background>
        <Content>
  //modal 안의 contents 코드
         </ Content>
      </Background>
  );
};

export default Modal;

 

4 Portal, Modal 조건부 렌더링

import styled from "styled-components";
import ModalPortal from "../Components/Modal/Portal";
import Modal from "./Modal/Modal";

const Carousel = props => {
  const [onModal, setOnModal] = useState(false);

  const handleModal = () => {
    setOnModal(!onModal);
  };
  
  return (
    <>
      <Container>
    	<button onClick={handleModal}/>
		// ... 코드 생략 ...
        <ModalPortal>
          {modalOn && <Modal onClose={handleModal} />}
        </ModalPortal>
      </Container>
    </>
  );
};

export default Carousel;

 

 

 

728x90
반응형

'React' 카테고리의 다른 글

redux persist  (0) 2022.12.19
redux-toolkit  (0) 2022.12.19
Custom Hooks와 코드 분할/React.lazy()와 Suspense  (0) 2022.11.29
useMemo/useCallback  (0) 2022.11.28
Virtual DOM/ React Diffing Algorithm  (0) 2022.11.28
profile

Kimsora✨

@sorarar

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!

검색 태그

WH