최근 사이드 프로젝트 개발 도중, 스케줄(타임테이블)을 클릭하면 해당 학생의 명단을 Drawer에 표시하는 기능을 개발하게 되었다.
테스트 과정에서 여러 번 클릭해 보았더니, 실제 데이터의 수와 일치하지 않는 학생들이 Drawer에 표시되는 현상을 발견하였다.
위에 타임 테이블을 보면 14:30 ~ 15:00 목요일을 선택했을 때이다.
2명이지만 3명이 보여지는 현상이다.
그 때 "아, 맞다. key 설정을 제대로 하지 않았다"는 생각이 들어 기존에 사용하던
key={attendee.name}
에서
key={[attendee.name, attendee.age, index].join("-")}
로 변경하게 되었다.
이미 알고 있겠지만, React에서는 리스트 렌더링 시 각 항목을 고유하게 식별하기 위해 key를 반드시 고유하게 설정해야 한다.
리스트 형태의 자식 요소들을 렌더링할 때, React는 각 항목에 할당된 key를 사용하여 이전 Virtual DOM의 요소와 새 Virtual DOM의 요소를 매핑한다.
(내부적으로 React는 이 과정을 위해 해시맵과 유사한 구조를 활용한다고 한다.)
이 때,
중복된 key가 있는 경우: 동일한 key가 여러 항목에 할당되면,
React는 어떤 항목을 매핑할지 명확하게 결정할 수 없게 된다.
고유한 key가 있는 경우: 각 항목은 고유한 key를 통해 정확히 매핑되어,
변경된 항목만 업데이트하거나 재사용할 수 있다.
React는 새로운 Virtual DOM에 해당 key가 존재하면 이미 존재하는 DOM 요소를 재사용하려고 한다.
만약 동일 key가 중복되어 있다면, 어느 항목을 재사용해야 할지 판단하는 과정에서 내부 로직에 따라 한 항목만 선택되고 나머지는 제대로 제거되지 않을 수 있다.
예를 들어, 동일한 이름을 가진 두 개 이상의 항목이 모두 "Alice"라는 key를 가진 경우, 새롭게 데이터가 업데이트되어 실제로는 4명이 아닌 3명의 학생만 존재함에도 불구하고, React는 "Alice"라는 key를 가진 요소를 재사용하려고 한다.
이 과정에서 어떤 "Alice" 요소를 재사용해야 할지 판단하기 어려워지며, 결과적으로, 실제 데이터에서는 제거된 항목이지만 이전 렌더링의 DOM 요소가 그대로 남아 있게 되어, 화면에 불필요한 요소가 나타나게 된다.
따라서, key는 반드시 고유해야 한다!
그래서 이름뿐 아니라 나이, index 등의 정보를 조합하여 고유한 값을 생성했었다.
이제, 박병훈이라는 학생이 없어진걸 확인하게 되었다.
갑자기 전 동료였던 병훈이형이 그립군요
머리 속에서는 동일한 key를 사용하면 안 된다는 사실은 이미 알고 있었지만, 이 문제 상황이 왜 발생하는지 궁금해 잊지 않기 위해 정리해 보았다.