이 글에서는 중요하지만, 그냥 지나치기 쉬운 기능들을 정리해보려한다.
이 글에서 알아볼 것
- Fragment
- Portal
1. Fragment
앞서 우리는 리액트의 기본개념을 알아보면서 JSX 코드에 대해서 살펴보았다.
JSX 코드는 자바스크립트 코드와 HTML 코드를 동시에 활용할 수 있다는 점에서 굉장히 자유로운 개념이라 느꼈었다.
하지만, 이런 JSX 코드에도 제한사항이 존재한다.
- JSX 코드 제한사항
- 루트 수준의 JSX 요소들이 인접해있으면(래핑되어있지않으면) 에러 발생
- 즉, 루트 수준의 JSX는 반드시 한개여야한다
- 왜냐하면, 이를 반환하거나, 변수등에 저장하기 위한 제약조건이다.
- 이렇게 글로만 보면 어렵게 보이거나, 잘 와닫지 않지만 자바스크립트를 생각해보면 쉽게 이해가 간다.
- 자바스크립에서 return은 오직 하나의 값만 가능했다. (객체, 배열또한 하나의 값이다.)
- 리액트도 결국 index.js에서 return을 하여 index.html에서 렌더링하는 방식이라는 걸 앞의 글을 통해서 우리는 알고있다.
- 즉, 리액트도 결국 return은 오직 하나의 값만 가능하다는 뜻이다.
- 해결방법은 뭘까??
- 간단하게 루트 수준의 JSX를 하나로 만들고 래핑하면된다 (div등으로..)
- return을 배열로한다…
- 하지만 이 방법은 잘 사용하지 않는다.
- 왜냐하면, 바로 앞에 글에서 배열로 작업할 때 key prop을 고려해야한다는 것을 살펴봤듯이..굉장히 귀찮아진다.
- 그러면, 1번을 이용하면 모든것이 해결된걸까? 아니다, 이는 다른 문제인 div soup라는 문제를 낳는다.
- 1~2번정도 div로 감싼다고 문제가 발생하지 않는다, 다만 앱이 커져서 div로 10번정도 감싼다고 생각해보자..
- 여기서 사용된 div중에 의미가 있는 div도 존재하겠지만. 대부분이 래핑을 위한 의미없는 div다
- 이는 스타일링에 영향을 줄 수 있다
- 성능 저하의 문제도 발생할 수 있다.
- 그러면 궁극적인 해결방법은 뭘까?
- Fragment
- 앞서 살펴본 제한사항을 궁극적으로 해결하는 방법은 하나다.
- html 요소를 DOM에 렌더링해주지 않는것으로 감싸주면 된다…근데 그게 뭘까?
- 앞서 살펴본 제한사항을 궁극적으로 해결하는 방법은 하나다.
1. Wrapper 컴포넌트
const Wrapper = (props) => {
return props.children;
};
export default Wrapper;
- Wrapper라는 컴포넌트를 생성하고 오직 props.children만을 반환준다
- 그리고 이 컴포넌트를 사용하여 div대신 감싸준다
2. Fragment
- 1번과 똑같은 행동을 하는 컴포넌트다.
- 차이점은 위에는 우리가 만든것이고 Fragment는 리액트에서 제공해준다는 점이다.
3. <> ~ </>
- 마찬가지로 위에 기능들과 똑같은 행동을 한다
- 다만, 이방법은 프로젝트 설정에 따라 지원하지 않을 수도 있다.
2. Portals
<Fragment>
<div className="modal">
<h2>Dummmy Text</h2>
</div>
<form>
<label></label>
<input></input>
</form>
</Fragment>
- 위의 코드는 문제가 있을까?
- 없다…없지만 모달부분이 약간 거슬린다
- 모달은 페이지 위에 표시되는 오버레이다...즉, 모든 것 위에 존재해야한다.
- 근데 위의 코드는
- 다른 코드와 중첩 및 인접해있다 → 의미적으로 좋은 코드가 아님
- 상황에 따라 다르겠지만 해당 코드가 html 요소 매우 안쪽에 위치되어있을 수도 있다. → 구조적으로 좋은 코드가 아님
- 등의 이유로 의도와 다른 결과를 발생시킬 수 있다
- 이때 사용하는 기능이 Portal이다.
- 없다…없지만 모달부분이 약간 거슬린다
- Portal
- 위의 문제를 해결해주는 것이 Portal 기능이라 말했다. 어떻게 사용할까?
- Portal은 두가지가 필요하다
- 컴포넌트를 이동시킬 장소
- 컴포넌트에게 그 곳에서 포털을 가져야 한다고 알려한다
컴포넌트를 이동시킬 장소란?
=> public 폴더에 존재하는 index.html에 루트 앞 위치다.
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="backdrop-root"></div>
<div id="modal-root"></div>
<div id="root"></div>
컴포넌트에게 그 곳에서 포털을 가져야 한다고 알려한다
const Backdrop = (props) => {
return <div className={classes.backdrop} onClick={props.onConfirm}></div>;
};
const Modal = (props) => {
return (
<Card className={classes.modal}>
<header className={classes.header}>
<h2>{props.title}</h2>
</header>
<div className={classes.content}>
<p>{props.message}</p>
</div>
<footer className={classes.actions}>
<Button onClick={props.onConfirm}>Okay</Button>
</footer>
</Card>
);
};
const ErrorModal = (props) => {
return (
<Fragment>
{ReactDOM.createPortal(<Backdrop onConfirm={props.onConfirm}></Backdrop>, document.getElementById("backdrop-root"))}
{ReactDOM.createPortal(
<Modal title={props.title} message={props.message} onConfirm={props.onConfirm}></Modal>,
document.getElementById("modal-root")
)}
</Fragment>
);
};
이번 글에서 살펴본 내용들도 중요하지만,
앞에서 살펴본 내용들이나, 이후에 살펴볼 내용들에 비해 간단하고 이해가 쉽게가는 내용들이다.
따라서, 이 내용들은 어떻게 사용하는지 보다는 왜 사용하는지를 알고있는것이 중요할 것 같다.
'OLD > React' 카테고리의 다른 글
[React] React useEffect 훅 (0) | 2023.03.01 |
---|---|
[React] React에서 사용자 입력을 컨트롤 하는 두 가지 방법 (state vs ref) (0) | 2023.02.26 |
[React] React "key" prop (react에서 배열 활용 시 발생하는 Warning 해결하기) (0) | 2023.02.24 |
[React] React 스타일링 하는 방법 3개 (인라인&일반CSS, styled-components, CSS 모듈) (0) | 2023.02.23 |
[React] React에서 데이터를 활용하는 방법(state, 입력값 컨트롤, 이전 데이터 활용, 데이터 끌어올리기) (0) | 2023.02.21 |