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>
=>
- Fragment는 불필요한 DOM node의 생성을 막기 때문에 메모리를 적게 사용한다.
- 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;
'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 |