map메서드를 사용하는 부분에서 다음과 같은 에러가 발생했다.
처음에는 오류 문구 그대로 key prop을 주지 않아서 발생한 거라 생각해서 빠진 부분을 수정했는데 오류는 해결되지 않았다!🙀 심지어 수정하고나서 map을 사용한 다른 부분들도 이런 오류가 추가로 발생했다.
map 함수의 규칙 : 사용될 요소의 최상위 요소에 key 값을 부여해야함.
원인은 다음의 규칙을 어겨서 오류가 난 것이었다. 내가 작성한 코드로 설명을 하자면
{e.lnb.map((el) => (
<>
<li className="lnb-item" key={el}>
<a href="#">{el}</a>
</li>
</>
))}
jsx는 최상위에 무조건 감싸는 엘리먼트가 존재해야한다. 하지만 감싸는 엘리먼트가 스타일도 없고 역할도 없다면 저렇게 빈 태그
를 사용해 작성할 수 있다.
그래서 map메서드 내에서도 저렇게 코드를 작성했다. 그리고 저 빈 태그는 의미가 없기에 li 태그에 key값
을 줘야한다 생각했다.
하지만 위 코드는 li 태그가 내부의 a 태그를 감싸는 최상위 감싸는 엘리먼트
이기 때문에 최상위 빈 태그
가 없어도 문법적으로 오류가 나지 않는다.
{e.lnb.map((el) => (
<li className="lnb-item" key={el}>
<a href="#">{el}</a>
</li>
))}
이렇게 최상위 엘리먼트를 가져야한다는 규칙
도 map 함수의 규칙
도 모두 지키게 되었다.
그럼 다음의 경우를 보자
{data.map((category, index) => (
<>
<Category
dish={category.data}
category={category.key}
display={index === 0 ? "block" : isFold ? "none" : "block"}
/>
<Horizon
display={
index === data.length - 1 ? "none" : isFold ? "none" : "block"
}
/>
</>
))}
이 경우는 어떻게 해결해야 할까? 최상위 빈 태그
를 삭제한다면 jsx의 감싸는 최상위 엘리먼트를 가져야한다는 규칙
에 어긋나게 된다. 그런데 빈 태그에는 key prop을 줄 수 없다.
그래서 두 규칙을 모두 만족하기 위해 Wrapper
컴포넌트를 만들었다. 그리고 그 Wrapper
에다 key prop을 줬다.
const CategoryWrapper = styled.div``;
{data.map((category, index) => (
<CategoryWrapper key={category.key}>
<Category
dish={category.data}
category={category.key}
display={index === 0 ? "block" : isFold ? "none" : "block"}
/>
<Horizon
display={
index === data.length - 1 ? "none" : isFold ? "none" : "block"
}
/>
</CategoryWrapper>
))}
이렇게 하면 두 규칙을 모두 만족하며 오류를 해결할 수 있다.
두번째 케이스의 해결법을 다시 생각해보자.
const CategoryWrapper = styled.div``;
.........................👀❓
저렇게 의미없는 빈 컴포넌트를 만든다고?? 너무 비효율적인데...페이스북에서 저렇게 만들었을까....???
그래서 찾아봤더니 역시나 방법이 있었다. 리액트에서 제공하는 Fragment 컴포넌트를 사용하면 된다.
사실 계속 빈 태그라고 불렀던 것도 Fragment이다. 차이점은 빈 태그 형태로 된 Fragment
는 key prop을 줄 수 없지만 <Fragment>
에는 key prop을 줄 수 있다.
그럼 저 이상한 코드를 고쳐보자
import { Fragment } from "react";
{data.map((category, index) => (
<Fragment key={category.key}>
<Category
dish={category.data}
category={category.key}
display={index === 0 ? "block" : isFold ? "none" : "block"}
/>
<Horizon
display={
index === data.length - 1 ? "none" : isFold ? "none" : "block"
}
/>
</Fragment>
))}
👏👏👏👏👏👏👏👏👏👏👏 해 👏👏👏👏👏👏👏👏👏👏👏 결 👏👏👏👏👏👏👏👏👏👏👏