리스트에 key={index}를 썼다가 입력값이 엉뚱하게 섞인 이유
문제 발생
입력 필드가 있는 리스트에서 가운데 항목을 삭제했더니, 삭제 이후의 입력값들이 한 칸씩 밀려서 잘못된 항목에 표시되는 버그가 발생했습니다.
{items.map((item, index) => (
<input key={index} defaultValue={item.text} />
))}원인 분석
React는 리스트를 다시 렌더링할 때 key를 기준으로 "이전에 있던 어떤 엘리먼트와 지금 이 엘리먼트가 같은 것인지"를 판단합니다. key가 같다고 판단되면 React는 그 DOM 노드와 컴포넌트 상태(input의 defaultValue가 반영된 실제 DOM 값, 포커스 등)를 재사용합니다 — 새로 만들지 않습니다.
배열 인덱스를 key로 쓰면, 항목을 삭제하거나 순서를 바꿨을 때 인덱스는 그대로인데 실제 데이터는 다른 항목으로 바뀝니다. 예를 들어 3번째 항목을 지우면, 4번째였던 항목이 이제 인덱스 3을 갖게 됩니다. React 입장에서는 "key=3인 엘리먼트는 그대로 있다"고 판단해 그 DOM(과 그 안의 사용자 입력값, 포커스 상태)을 그대로 재사용하지만, 실제로는 전혀 다른 데이터 항목입니다 — 그래서 입력값이 엉뚱한 항목에 남아있는 것처럼 보입니다.
해결 방안
- 각 항목을 고유하게 식별하는 안정적인 값(DB의 id 등)을
key로 씁니다.
{items.map((item) => (
<input key={item.id} defaultValue={item.text} />
))}- 안정적인 id가 정말 없는 경우에만(예: 렌더링 시점에 한 번 생성되고 절대 재정렬/삭제되지 않는 정적 리스트) 인덱스를
key로 써도 괜찮습니다 — React 공식 문서도 이 조건에서는 인덱스 사용을 허용합니다. - 새로 추가하는 항목에 아직 서버가 부여한 id가 없다면, 클라이언트에서 생성 시점에 임시 고유 id(
crypto.randomUUID()등)를 만들어 부여합니다 — 배열 인덱스보다 안전합니다. - 이 문제는
key가 잘못되어도 콘솔에 명확한 에러가 뜨지 않고 그냥 조용히 상태가 잘못 섞이는 방식으로 나타나므로, 리스트 항목에 입력값/체크박스/포커스처럼 "항목별 상태"가 있다면 처음부터 안정적인 key를 쓰는 습관이 중요합니다.
댓글0
댓글을 남기려면 로그인이 필요해요. 로그인
아직 댓글이 없어요. 첫 의견을 편하게 남겨 보세요.