[React] 배열의 index를 key로 쓰면 안되는 이유

Jeongkuk Seo
sjk5766
Published in
5 min readApr 16, 2020

React 공식 Document를 보다가 아래 노란색으로 캡쳐한 부분을 보게 되었고 확인한 사항들을 정리합니다.

우선 문제가 발생하는 소스를 보겠습니다. Create-react-app 을 이용해 React 프로젝트를 생성했으며 App.js 단순히 아래 컴포넌트를 보여줄 뿐입니다.

코드를 간단하게 설명하면..

  • line 22, 23: 추가, 삭제 버튼. 추가 버튼을 누르면 정국 데이터를 list 앞에 추가하고 삭제를 누르면 철수를 삭제한다.
  • line 28: component가 관리하는 list 데이터를 map으로 loop 돌며 div 태그의 keyindex로 지정한다.

코드를 실행한 결과는 아래와 같습니다.

여기서 철수 input부분에 아래와 같이 데이터를 입력합니다.

그리고 추가 버튼을 누릅니다. 우리가 예상한 결과는 아래와 같을 겁니다.

하지만 실제 결과는 아래와 같습니다.

왜 이런 결과가 나왔는지 추가 버튼누르기 전 상황으로 돌아갑니다. DOM에서 key가 0 인 곳에 여기는 철수 데이터 가 있습니다.

우리가 추가 버튼을 누르면 list 데이터가 변경되면서 component가 re-render되고 index를 다시 mapping 합니다. 맨 앞에 추가된 정국 데이터에 key가 0이 mapping 됩니다. React는 key가 동일 할 경우, 동일한 DOM Element를 보여주기 때문에 아래와 같은 현상이 발생합니다.

이런 현상은 데이터를 삭제하는 부분에도 발생하게 됩니다.

이 상태에서 삭제를 누르면 철수 데이터를 삭제 하게 됩니다. 이 때 결과를 보면 아래와 같습니다. 마찬가지로 데이터가 변경되면서 re-rendering 되고 index가 0부터 다시 mapping 되면서 이전의 index가 0 이였던 철수 데이터가 영희에게 mapping 됩니다. 그리고 이는 분명히 우리가 원하는 결과와는 다릅니다.

Q1. 그럼 어떤 데이터를 key로 사용하면 될까요

List 데이터에서 Unique 한 값을 key로 사용합니다. 제 경험에 비춰서 가장 사용하기 쉬운 건 Database의 id 입니다. AUTO_INCREMENT 된 id값을 서버로 부터 받아서 사용합니다. id값이 아니더라도 unique 하다면 key로 사용할 수 있습니다.

만약 데이터에 Unique한 값이 없다면 아래와 같이 global 변수를 이용해 id를 생성하고 이를 key로 사용할 수도 있습니다.

counter = 1;function createNewTodo(text) {
return {
id: counter++,
text
}
}

Production 모드에서는 위 방법보다는 shortid를 사용하는게 좋다고 하네요.

var shortid = require('shortid');function createNewTodo(text) {
return {
id: shortid.generate(),
text
}
}

Q2. 그럼 절대로 배열의 index를 key로 사용하면 안되나요?

제가 참고한 Robin Pokorny 말에 의하면 아래 3가지를 만족 할 경우 안심하고 index를 key로 써도 된다고 이야기 했습니다.

  1. 배열과 각 요소가 static이며 computed 되지 않고 변하지 않아야 한다.
  2. 데이터 내부에 id로 쓸만한 unique 값이 없을 경우
  3. 데이터가 결코 reordered or filtered 되지 않을 경우

위 3가지를 만족하면 배열의 index를 key로 써도 된다는 것 같은데.. 어째 저는 데이터가 절대 변하지 않을 경우에 쓰라는 말 같기도 하네요..

--

--