
"알겠습니다! 저한테 맡겨주세요!"

헬리오스 탑은 리액트로 만들어졌습니다.
리액트는 UI를 구성하는 최소 단위인 컴포넌트들로 구성되어 있습니다.
이때 각각의 리액트 컴포넌트는 여러 요소를 그대로 반환할 수 없으며, 그렇기에 하나의 부모 요소로 묶어주어야 합니다.
예시를 살펴봅시다.


위와 같이 여러개의 JSX 요소를 그대로 반환하려고 하면,
리액트는 하나의 부모 요소가 필요하다는 오류를 발생시킵니다.


<div> 태그를 사용해 부모 요소로 묶어주었더니,
더 이상 오류가 발생하지 않습니다.
이제 HeliosTower.tsx 컴포넌트를 App.tsx에서 불러오면,
화면에 정상적으로 출력되는 것을 확인할 수 있습니다.


앗, 그런데 누군가 부모 <div> 태그에 css를 추가하는 장난을 쳐놨습니다.
<div> 태그에 빨간색 배경을 입혀서, 탑이 빨갛게 물들고 말았어요.
심지어 black-wrapper라고 스타일 클래스 이름을 지었으면서 red색깔로 물들이는 농락까지... (절대내실수가아님)

개발자 도구에서 DOM(Document Object Model) 구조를 확인해보면,
요소들을 감싸고 있는 부모 <div> 태그가 보입니다.
이렇게 계속 <div> 태그로 요소들을 감싸게 된다면, 누군가 쉽게 css를 추가해 탑의 모습과 구조를 엉망으로 만들거에요.
하지만 다행히도, 아예 DOM에 흔적을 남기지 않는 방법이 있어요.
바로, <Fragment> 를 사용하는 거예요!
Fragment로 감싼 요소들은 실제 DOM 결과물에 아무런 영향을 주지 않습니다.
리액트에서 흔히 사용하는 <> </> 문법이 <Fragment> </Fragment>의 축약형입니다.
Fragment로 엘리먼트를 그룹화하면 다른 컨테이너(<div> 등)으로 엘리먼트를 감싸는 경우와 달리,
레이아웃이나 스타일에 영향을 주지 않습니다.
Fragment 태그를 활용해 탑의 구조를 바꿔봅시다.


왼쪽은 정식 문법인 <React.Fragment>를,
오른쪽은 축약 문법인 <> </>를 사용해 태그를 감싸보았습니다.
개발자 도구에서 DOM 구조를 확인해보면,
두 경우 모두 실제 DOM에는 아무런 태그도 추가되지 않은 것을 볼 수 있습니다.

정말 실제 DOM에는 Fragment의 흔적이 전혀 남아 있지 않습니다!
🤔 그럼 항상 편하게 Fragment 축약 문법 <> </> 을 쓰면 되나요?
그렇다고 할 수 없습니다.
Fragment는 DOM에 흔적을 남기지 않기 때문에, 오히려 스타일을 남겨야 할 때는 적합하지 않습니다.
진짜 레이아웃이나 배경을 제대로 바꾸고 싶을 때는 아래 예시처럼 css를 적용할 수 있습니다.


아래와 같이 예쁘게 스타일이 적용된 것을 확인할 수 있습니다.

두 번째로, 축약형 <> </> 말고 <React.Fragment> </React.Fragment>를 사용해야 하는 때가 있습니다.
바로, key를 사용해야 하는 경우입니다.
리액트에서 반복을 통해 여러 요소들을 랜더링할 때는 각 요소에 key를 할당해야 합니다.
이때 key 할당은 축약형 문법 <> </> 에서는 할 수 없고, 정식 문법인 <Fragment> </Fragment> 에서만 가능합니다.
예시를 살펴봅시다!
export default function HeliosTower() {
const floors = ['100층', '99층', '앨리베이터', '2층', '1층', '아랫마을 입구'];
return (
<>
<h1>헬리오스 탑</h1>
{floors.map(floor => (
<>
<p>{floor}</p>
<button>이동버튼</button>
</>
))}
</>
)
}
map 메서드를 활용해 floors 배열 안에 있는 각각의 값들을 렌더링 하고 있는데요,
현재 반복 렌더링되는 각각의 최상위 요소에 key값을 주지 않고 있습니다.
key값이 없으면 아래와 같이 Each child in a list should have a unique "key" prop 에러가 뜹니다.

map의 결과물로 Fragment 여러 개가 나올텐데, 이들을 서로 구분할 key가 없다면
추가 / 삭제 / 순서 변경 시에 상태가 꼬일 수 있습니다.
즉, 각 요소에 key를 할당해야 하는데, Fragment 축약형 <> </> 을 썼을 경우 key를 할당하지 못합니다.
이런 경우에는 정식 문법 <React.Fragment> </React.Fragment> 를 사용하거나, <div> </div> 태그를 사용하여
key값을 할당해 주어야 합니다.
수정한 코드를 살펴봅시다.
import React from "react";
export default function HeliosTower() {
const floors = ['100층', '99층', '앨리베이터', '2층', '1층', '아랫마을 입구'];
return (
<>
<h1>헬리오스 탑</h1>
{floors.map((floor) => (
<React.Fragment key={floor}>
<p>{floor}</p>
<button>이동버튼</button>
</React.Fragment>
))}
</>
)
}
<React.Fragment key={floor}> 이 부분을 보시면 됩니다.
축약형 태그 대신, React.Fragment 정식 태그를 사용하여 각각의 요소에 임시로 floor 값을 키로 넣어주었습니다.

이제 에러 메세지가 나오지 않습니다!
.
.
.
.
정리해 볼까요?
Fragment는 여러 요소를 하나로 묶어야 할 때,
DOM에 불필요한 태그를 추가하지 않기 위한 도구입니다.
Fragment에는 기본 문법과 축약 문법이 존재합니다.
단순히 구조를 정리하는 용도라면 Fragment를,
레이아웃이나 스타일의 기준이 필요하다면
의미 있는 컨테이너 요소를 사용하는 것이 좋습니다.
다만 key를 사용해야 하는 경우에는
축약형 대신 정식 Fragment 문법이나
다른 컨테이너 요소를 사용해야 합니다.
✨ 프론트엔드 경험치 10xp 를 얻었습니다.✨