[React] map 함수 를 이용해 여러개의 컴포넌트 렌더링 시 key 를 꼭 포함해야하는 이유

Maria Kim·2021년 11월 19일
0

React 공식 문서
벨로퍼트 리액트

물론 map 함수 를 이용해 여러개의 컴포넌트 렌더링 시 key 를 포함하지 않으면 경고창이 뜨기 때문에 경고창을 없애기 위해 key 를 포함시킨다.

하지만 왜??!! 꼭 넣으라고 하는 걸까?

이는 react 가 효율적으로 리렌더링하는데, 즉 성능에 큰 역할을 하기 때문이다.

예시

만약 ['a', 'b', 'c', 'd'] 가 있고

'b' 를 삭제한다면

key 가 없을때

'a'-> 'a' , 'b' -> 'c' , 'c' -> 'd', 'd' -> 삭제 로 변경할 것이다.

각 key 로 이름을 붙여주지 않으면 react 는 어디가 삭제되고 어디가 변경됐는지 모르기 때문이다.

key 가 있을때

  const feed1Comment = [
    {
      nickName: 'tjdgus05',
      commentText: '이쁘다~~',
      commentId: 1,
      heartActive: true,
    },
    {
      nickName: 'ria',
      commentText: '하늘이 정말 이뻤네~',
      commentId: 2,
      heartActive: false,
    },
    {
      nickName: 'peter',
      commentText: '오늘 나갔었구나',
      commentId: 3,
      heartActive: false,
    },
  ];
{comments.map((comment, i) => (
         <Comment
           onHeartClick={onHeartClick}
           onDeleteComment={onDeleteComment}
           comment={comment}
           key={i}
         />
))}

이렇게 key 값을 주면 어떤 엘리먼트가 삭제되고 어떤 엘리먼트에서 수정이 되고 되지 않았는지 React가 정확히 인식할 수 있게 된다.

이를 통해, 수정이 되지 않은 부분은 그대로 두고 변경된 부분만 리렌더링한다. 우리가 생각했던 대로 필요한 부분만 리렌더링 됨을 알 수 있다.

index 를 key 로 사용 하면 안되는 이유

React 가 DOM elements 인식하는 유일한 방법은 key 를 통해서이다.
하지만 key 를 지정해 주지 않으면 index 를 key 로 사용한다.

key 를 사용하지 않았을 때 모든 엘리먼트들을 변경한 것과는 확연히 다른 성능 차이를 보임을 알 수 있다.

또한, 더 큰 문제는 우리가 생각한 대로 react 가 움직이지 않을 수 있기 때문이다.

item을 새로 추가하거나 삭제하면 내가 생각한 그 item 이 삭제되지 않고 다른 아이템이 수정되어 없어진 것처럼 보이게 되게 될 수 있다. 또, 이 상태에서 sort를 하면 react 는 정말 혼돈의 카오스가 된다. 이를 map 해서 나에게 보이면 이제 내가 혼돈의 카오스가 될 수 있다.

(Robin Pokorny’s) Index as a key is an anti-pattern 자세한 내용은 여기서 확인해 볼 수 있고

Index as a key is an anti-pattern 예시 에서 직접 item을 추가해보며 어떤 문제가 생기는지 확인해 볼 수 있다. 한번해보면 다음부턴 무조건 key에 index가 아닌 고유한 값을 사용하게 될 것이다.

key 에 대해

  • key는 html id 와 다르게 형제 사이에서만 고유한 값이면 된다

좋은 key (Robin Pokorny 추천 방법)

  1. item 이 만드는 단계에서 id 만들어 주기
let itemId = 1;

const createItem = (text) => {
id: itemId++,
text
}
  1. id 를 nanoid로 만드는 방법 <- 적극 추천 방법
import { nanoid } from 'nanoid';

const createItem = (text) => {
id: nanoid(),
text

key 를 작성하지 않아도 될 때

하지만 절대 변경사항이 없는 컴포넌트들을 map 하는 거라면 key를 index로 해도 되지 않을까 조심스럽게 생각해 본다.

Robin Pokorny는 실제로 아래 3가지를 모두 만족하는 상황이라면 index 를 키로 사용해도 안전할 것이라고 했다.
1. 리스트나 items 가 정적이고, 계산되거나 수정하지 않는 것일 때
2. 리스트에 있는 item 들이 id가 없을 때 (id 가 있다면 그냥 왠만하면 쓰라는 것 같다)
3. 리스트가 절대 재배치되거나 필터 될 일이 없을 때

결론

  • 정말 진짜 아무리 봐도 key 가 필요 없어 보일 때 말고는(사실 절대일 때가 잘 없다...)
  • 그냥 고유한 값을 key에 넣어 사용하자 :) 이렇게 하면 최소한 에러가 날 수 있는 하나의 변수는 사라진 셈이다!! 얼마나 좋은가!
profile
Frontend Developer, who has business in mind.

0개의 댓글