⭐ 8편 — 리액트 리스트 렌더링 완전 정복: key가 중요한 이유와 성능 문제까지 한 번에 이해하기
리액트로 화면을 만들다 보면
가장 자주 하는 작업 중 하나가 바로 배열 데이터를 화면에 반복 렌더링하는 것입니다.
게시글 목록
쇼핑몰 상품 리스트
사용자 목록
댓글 리스트
이런 기능들은 모두 배열을 map으로 돌려 렌더링하게 됩니다.
그런데 이 리스트 렌더링에서 가장 중요한 개념이 바로 key 속성입니다.
많은 초보자들이 이 key를 “그냥 넣으라고 해서 넣는 값” 정도로 생각하는데,
실제로는 리렌더링 성능에 직접적인 영향을 주는 핵심 요소입니다.
이번 글에서는 key가 왜 필요한지,
그리고 어떤 값을 key로 써야 하는지까지 실전 기준으로 설명해드릴게요.
✅ 1. 기본 리스트 렌더링 패턴.
리액트에서 리스트를 그릴 때 가장 자주 쓰는 구조는 아래처럼 map을 사용하는 방식입니다.
const items = ["사과", "바나나", "포도"];
return (
<ul>
{items.map(item => (
<li>{item}</li>
))}
</ul>
);
이 코드는 화면에는 잘 보이지만, 사실 경고가 뜹니다.
Warning: Each child in a list should have a unique "key" prop.
그 이유는 바로 key를 넣지 않았기 때문입니다.
🔥 key란 무엇인가?
간단하게 말하면,
✔ key는 React가 “어떤 요소가 어떤 데이터인지” 추적하는 식별자입니다.
리스트에서 항목이 추가되거나 삭제되면
리액트는 key를 기준으로
기존 요소인지
새로 추가된 요소인지
삭제되는 요소인지
이런 변화를 인식하게 됩니다.
🔍 key가 없으면 어떤 문제가 발생할까?
예를 들어 리스트에서 하나의 항목만 제거되었는데,
리액트는 어떤 요소가 삭제되었는지 정확히 알 수 없어 전체 리스트를 재비교하게 됩니다.
그러면
불필요한 리렌더링
UI가 순간적으로 꼬임
입력창 같은 컴포넌트가 리셋되는 문제
등이 발생합니다.
즉, key는 성능과 UI 안정성에 직접적인 영향을 줍니다.
✅ 2. key를 넣은 올바른 리스트 렌더링
<ul>
{items.map((item, index) => (
<li key={item}>{item}</li>
))}
</ul>
여기서는 item이 유일한 값이므로 key로 사용해도 괜찮습니다.
❗ 하지만 가장 위험한 key 사용법: index
많은 초보자들이 다음처럼 index를 key로 사용합니다.
<li key={index}>...</li>
하지만 index는 권장되지 않습니다.
🔥 왜 index를 key로 쓰면 안 좋을까?
이유는 간단합니다.
상황 예시
리스트:
0: "사과"
1: "바나나"
2: "포도"
여기서 "바나나"를 삭제하면 리스트가 이렇게 바뀝니다:
0: "사과"
1: "포도"
그런데 index를 key로 쓰면 리액트는 이렇게 판단합니다:
원래 index 2(포도)가 이제 index 1이 되었으니 “새로운 요소”로 인식
→ UI가 불필요하게 다시 렌더링됨
이런 문제 때문에
데이터의 고유한 값(예: id)을 key로 사용해야 합니다.
✅ 가장 좋은 key 선택 기준
✔ 1) 데이터가 가진 고유 ID
예: 유저 ID, 게시글 ID, 상품 번호 등
✔ 2) 절대 변하지 않는 값
(렌더링 때마다 달라지는 값은 절대 사용하면 안 됨)
✔ 3) 배열 index는 최후의 보류 선택(거의 쓰면 안 됨)
⭐ 실전 예제: 서버 데이터 기반 리스트
가장 일반적인 실무 예제입니다.
const products = [
{ id: 101, name: "키보드" },
{ id: 102, name: "마우스" },
{ id: 103, name: "모니터" },
];
return (
<ul>
{products.map(product => (
<li key={product.id}>{product.name}</li>
))}
</ul>
);
이렇게 ID를 key로 사용하면 최적화가 잘 작동합니다.
🔥 key를 잘못 사용해서 발생하는 실제 문제 사례
✔ 1) 리스트가 리렌더링될 때 입력값이 초기화됨
폼이 포함된 리스트에서 index를 key로 쓰면 자주 발생합니다.
✔ 2) 애니메이션이 깨짐
React Transition, Framer Motion 등 애니메이션 사용하는 UI에서 특히 심각합니다.
✔ 3) “삭제/추가” 연산 시 엉뚱한 요소가 업데이트됨
리액트가 같은 요소인지 판단하지 못해 생기는 문제입니다.
🚨 초보자가 리스트 렌더링에서 실수하는 4가지
❌ 1) key를 아예 넣지 않음
React가 항목을 제대로 비교하지 못함
❌ 2) key로 index 사용
정렬, 추가, 삭제 시 문제가 바로 발생
❌ 3) key가 중복되는 값
중복된 key는 아무 의미가 없습니다.
오히려 업데이트 로직이 꼬입니다.
❌ 4) key를 위한 랜덤값 생성
Math.random()으로 만든 key는 렌더링마다 바뀌기 때문에 최악입니다.
✨ 마무리: key는 “리액트가 리스트를 관리하는 기준”
리스트 렌더링은 단순히 map으로 돌리는 작업이 아닙니다.
리액트가 어떤 요소를 어떤 값과 연결해서 추적하는지를 결정하는 중요한 작업입니다.
key를 올바르게 사용하면
✔ 성능이 좋아지고
✔ UI 변화가 안정적이고
✔ 버그도 크게 줄어듭니다.
이번 글을 이해했다면
실무에서 리스트를 다루는 능력이 확 올라가게 될 거예요.
'리액트' 카테고리의 다른 글
| ✅ 11편. 리액트 프로젝트 폴더 구조 설계 Best Practice (0) | 2025.11.26 |
|---|---|
| ⭐ 10편 — 리액트에서 비동기 처리 완전 정리: fetch, axios, async/await, useEffect 패턴까지 실전 가이드 (0) | 2025.11.25 |
| ⭐ 9편 — 리액트 상태 관리 기본기: Context API vs Redux 실전 비교, 초보자도 알 수 있게 정리 (0) | 2025.11.25 |
| ⭐ 7편 — React Router 완전 정복: 페이지 이동부터 동적·중첩 라우팅까지 실전 가이드 (0) | 2025.11.25 |
| ⭐ 6편 — 리액트 리렌더링과 성능 최적화 완전 정복: React.memo, useCallback, useMemo 제대로 쓰는 법 (0) | 2025.11.25 |
| ⭐ 5편 — useRef 완전 정복: DOM 제어부터 값 저장까지 실무에서 자주 쓰는 패턴 총정리 (0) | 2025.11.25 |
| ⭐ 4편 — 리액트 핵심 Hook 완전 정복: useState와 useEffect 제대로 쓰는 법 (0) | 2025.11.25 |
| ⭐ 3편 — 초보자 80%가 헷갈리는 Props vs State: 완벽하게 이해하는 쉬운 설명 (0) | 2025.11.25 |