기본적으로, 컴포넌트화 하지 않고 리액트에서 map함수를 사용하는 방법은 다음과 같다.
주어진 배열에 따라서 렌더링 되어야 할 부분에서 {}를 사용해 자바스크립트를 사용할 것을 명시해주고, map함수를 통해 렌더링 될 부분을 작성해주면 된다.
<div className="feed__comments">
{commentsArr.map((item, index) => {
return (
<div className="feed__comment__item">
<span className="avatar__id">canon_mj</span>
<span>{item}</span>
})}
</div>
🛑 그러나 위 코드를 실행하면, 리스트 각 항목에 key값을 넣어야 한다는 경고가 표시된다. 그럼 그 key값은 무엇이고 왜 넣어야 할까?
Key는 React가 어떤 항목을 변경, 추가 또는 삭제할지 식별하는 것을 돕습니다. key는 엘리먼트에 안정적인 고유성을 부여하기 위해 배열 내부의 엘리먼트에 지정해야 합니다.
리액트 공식문서에 따르면, key는 (point 1! 엘리먼트에 안정적인 고유성을 부여하기 위해) (point2! 배열 내부의 엘리먼트에 지정)해야 한다고 한다. 이게 무슨말일까?
// 전
<ul>
<li>Dog</li>
<li>Cat</li>
</ul>
//후
<ul>
<li>Dog</li>
<li>Cat</li>
<li>Rabbit</li>
</ul>
위의 경우처럼 맨 마지막에 새로운 리스트가 생겨야 한다면, React는 두 트리에서 <li>Dog</li>
와 <li>Cat</li>
이 일치하는지 확인 후 마지막으로 첫 번째 트리에 <li>Rabbit</li>
이 없으므로 추가해준다. 여기까지 보면 무엇이 크게 무리가 없어 보이나, 문제는 리스트의 맨 앞에 엘리먼트가 추가되는 경우이다.
// 전
<ul>
<li>Dog</li>
<li>Cat</li>
</ul>
//후
<ul>
<li>Rabbit</li>
<li>Dog</li>
<li>Cat</li>
</ul>
위와 같이 엘리먼트가 추가되는 경우, 리액트는 차이점이 발생하는 <li>Rabbit</li>
만 앞에 넣어주는 것이 아니라, <li>Dog</li>
<li>Cat</li>
종속 트리는 유지하면서 그 자식들만 변경한다. 즉, Rabbit의 자식들이 Dog안으로 들어가며, Dog의 자식들은 Cat안으로, 그리고 마지막으로 Cat안에 있던 자식들이 새로 생겨난 트리 안으로 들어가게 되는 거대한 비효율이 발생하게 되는 것이다.
위와 같은 문제를 해결하기 위해 생겨난 것이 바로 이 Key라는 친구인 셈이다.
자식들이 Key를 가지고 있다면, React는 key를 통해 기존 트리와 이후 트리의 자식들이 일치하는지 확인하기 때문에, 변환작업이 우리가 예상한 대로 수월하게 진행될 수 있다.
import Comment from "Comment.js";
<div className="feed__comments">
{commentsArr.map((item, index) => {
return <Comment key={index} comment={item} />;
})}
</div>
// Comment.js
const Comment = ({ comment }) => {
return (
<div className="comment">
<span className="avatar__id">canon_mj</span>
<span>{comment}</span>
<span className="feed__comment__reactions">
<i className="fa-solid fa-x" />
<i className="fa-regular fa-heart" />
</span>
</div>
);
};
위 작성 예시처럼 key값은 각각의 컴포넌트 엘리먼트에 주는 대신, 배열의 Comment안에 부여해야 한다는 것이다. 위의 경우 props은 {key, comment}를 가지고 있는 객체가 되며, 구조분해할당 문법으로 받아올 때에는 {comment}로 반환할 내용을 가져와줬다.
const mydata = [ "text1", "text2", "text3"]
const mydata = [{text: "text1", id : 0}, {text: "text2", id : 1}, {text: "text3", id : 1}
인덱스를 key로 사용 중 배열이 재배열되면 컴포넌트의 state와 관련된 문제가 발생할 수 있습니다. 컴포넌트 인스턴스는 key를 기반으로 갱신되고 재사용됩니다. 인덱스를 key로 사용하면, 항목의 순서가 바뀌었을 때 key 또한 바뀔 것입니다. 그 결과로, 컴포넌트의 state가 엉망이 되거나 의도하지 않은 방식으로 바뀔 수도 있습니다.
위 인용문이 무슨 말인지는 아래 리액트 공식문서에서 제공하는 예제를 보면 더 쉽게 이해할 수 있다.
위쪽의 사진처럼 key에 고유한 id를 부여한 경우, 값을 앞에서부터 추가해도 id값과 추가하는 값이 일치되지만 아래쪽의 사진처럼 key에 index번호를 부여한 경우, 값을 앞에서부터 추가하려면 컨텐츠가 꼬이게 되는 현상이 발생한다.