메인 프로젝트 상세페이지에서 위와 같이 리스트의 각 자식들이 유니크한 key prop을 가져야 한다는 에러가 발생하였다.
상세페이지에서 map
을 적용하여 렌더링되고 있는 리스트들은 review, talk, talk comment 총 3가지이다.
정말 요상한 것은!!! 이미 각 리스트에게 key로 각 리스트의 id
를 넘겨주고 있었는데도 해당 에러가 발생한다는 것이다 😢
리액트 공식 문서에 따르면 키는 형제 사이에서만 고유하면 된다고 한다.
review는 다른 태그로 감싸져 있어서 괜찮지만, talk와 talk comment는 같은 레벨에 있는 형제 관계인 것을 확인했다!
lists.reviews.data.map((review) =>
<DetailReviewList
key={review.reviewId}
...
/>
);
...
lists.talks.data.map((talk) => (
<>
<DetailTalkList
key={talk.talkId}
...
/>
{talk.talkComments &&
talk.talkComments.map((retalk) => {
<DetailTalkList
// 📌 적용한 부분!
key={`${retalk.talkCommentId.toString()}-retalk`}
...
/>;
})}
</>
));
그래서 talk와 talkComment의 id
가 겹쳐서 에러가 날 수도 있겠구나! 싶어서 talkCommentId
뒤에 retalk
라는 문자를 붙여 유니크한 key로 만들었다.
그러나... 여전히 에러가 사라지지 않아 콘솔에 data를 찍어 확인해보니, 에러가 발생하는 해당 페이지에서는 애초에 talk와 talkComment의 id
가 중복되는 부분이 없었다. 😢
lists.talks.data.map((talk) => (
<> // 📌 문제!!
<DetailTalkList
key={talk.talkId}
...
/>
{talk.talkComments &&
talk.talkComments.map((retalk) => {
<DetailTalkList
key={`${retalk.talkCommentId.toString()}-retalk`}
...
/>;
})}
</> // 📌 문제!!
));
해당 talk에 talkComments가 있을 경우에는 2개 이상의 리스트가 렌더링되기 때문에, 이 리스트들을 감싸주기 위해 <>...</>
를 사용했었는데 바로 이 래퍼 태그에 key prop이 없던 것이 문제였다!
그러나 <key={...}>
로는 key를 전달할 수가 없어서 리액트 공식 문서를 확인해보니 명시적인 <Fragment>
태그를 사용하면 key를 전달할 수 있음을 알게 되었다!
이게 새로운 공식 문서에 나와있다니.. 나 같은 사람이 많았나 싶다 😂
import { Fragment } from 'react';
lists.talks.data.map((talk) => (
<Fragment key={talk.talkId}>
<DetailTalkList
key={talk.talkId}
...
/>
{talk.talkComments &&
talk.talkComments.map((retalk) => {
<DetailTalkList
key={retalk.talkCommentId}
...
/>;
})}
</Fragment>
));
드디어 에러를 해결했다!!!!!!1 🥳
React.Fragment
를 사용하기 위해 구조분해할당으로 Fragment
를 import
해온 후, Fragment의 축약 버전으로 작성했던 <>
를 <Fragment>
로 바꿔, key를 적용하였다!
메인 프로젝트 진행하던 당시부터 지금까지 계에에속 신경쓰였었는데 진작에 공식 문서 좀 볼 걸 그랬다... 😢
심지어 <>
이 친구가 <React.Fragment>
의 단축 문법이라는 것도 처음 알았다...
그래도 옛날 같았으면 에러를 공식 문서에서 찾아서 해결할 생각은 하지도 못했을텐데
최근에는 잘 안되거나, 에러가 발생하면 공식문서를 가장 먼저 보게 되는 것 같다
역시 공식문서가 괜히 공식이 아니구나~
참고: 리액트 공식문서