Post

리액트에서 index를 key값으로 사용해도 될까?

리액트에서 index를 key값으로 사용해도 될까?

리액트에서 리스트 렌더링 시 key는 컴포넌트의 식별자 역할을 한다. 적절한 key를 사용하면 리렌더링 효율이 높아지고, 불필요한 상태 초기화나 예기치 않은 UI 버그를 방지할 수 있다. 이 글에서는 왜 고유한 key가 필요한지, 그리고 key로 사용할 고유 값을 생성하는 다양한 방법을 정리해보았다.


왜 고유한 key가 필요할까?

리액트는 리스트의 각 요소를 식별하기 위해 key 값을 사용한다. 이 값이 안정적이고 고유해야 렌더링 동작을 정확히 추적할 수 있다.

❗ index를 key로 쓰면 안 되는 이유

  • 배열에 요소가 추가/삭제/정렬되면 index 값이 바뀜
  • 리액트는 변경된 위치의 요소를 다른 요소로 오판할 수 있음
  • 그 결과

    • 불필요한 재렌더링 발생
    • input 값 초기화나 포커스 이동 같은 상태 꼬임 버그 발생

정적인 리스트(순서가 절대 변하지 않는 경우)를 제외하면 index 사용은 지양해야한다.


key로 사용할 고유 값을 생성하는 방법

리액트 key는 데이터의 정체성을 나타내는 값이어야 한다다.


1. 서버에서 제공하는 고유 ID 사용

예: DB의 id, 백엔드에서 내려주는 uuid

1
items.map(item => <TodoItem key={item.id} {...item} />)

✔ 변하지 않으므로 가장 안정적 ✔ 목록이 동적으로 변해도 문제 없음


2. 여러 필드를 조합해 고유 값 만들기

백엔드 ID가 없다면, 데이터의 특징을 조합해 고유성을 확보할 수 있습니다.

1
key={`${item.username}_${item.title}`}

단, 조합한 필드 값이 변한다면 key도 변하므로 신중히 사용해야 합니다.


3. UUID 생성하기

라이브러리 예: uuid, nanoid

1
2
3
import { v4 as uuid } from "uuid";

items.map(item => <Post key={uuid()} {...item} />)

주의: 렌더링 중 매번 uuid()를 호출하는 것은 비추천

  • 렌더링 때마다 key가 바뀌어 리액트가 모든 요소를 새로 만든다고 판단함

✔ 해결 방법 → 데이터를 준비하는 시점(렌더링 이전)에 UUID를 부여해야 함

1
const listWithIds = items.map(item => ({ ...item, key: uuid() }));

데이터의 인덱스를 사용해도 되는 경우

index 사용이 허용되는 매우 제한적인 상황:

  • 리스트가 완전히 정적일 때 (변경·삭제·정렬 없음)
  • UI 효과만 있는 형태 (ex. 간단한 애니메이션 요소들)

예:

1
2
const colors = ["red", "blue", "yellow"];
colors.map((color, idx) => <li key={idx}>{color}</li>)

마무리

리액트에서 key는 단순한 배열 인덱스나 식별자가 아니라, 컴포넌트의 정체성을 결정하는 중요한 값이다. 상황에 따라 적절한 고유 값을 선택하고, 가능하면 안정적으로 변하지 않는 ID를 사용하는 것이 좋다.


END

This post is licensed under CC BY 4.0 by the author.