[React] 리스트 렌더링 시 key props가 꼭 필요한 이유
key props
-
리렌더링 발생 시 current tree와 workInProgress tree 간 변경 사항 확인 필요
- 두 트리에서 같은 컴포넌트인지 구별하는 값 중 하나:
key props
- 만약 key가 없다면, 파이버 트리 구조에서 형제 컴포넌트 구분하기 위한 필드값인 sibling index만으로 판단하게 됨
- 두 트리에서 같은 컴포넌트인지 구별하는 값 중 하나:
-
리스트나 조건부 렌더링 시, 리렌더링 간 변화한 컴포넌트를 추적하기 위해 key를 사용
- key가 같으면 React는 컴포넌트를 재사용
- key가 바뀌면 React는 이전 컴포넌트를 언마운트하고 새로운 걸 마운트함
<ul>
{items.map((item) => (
<li key={item.id}>{item.text}</li>
))}
</ul>
🚨 key props로 index를 사용하면 위험하다
- 리스트가 추가/삭제/순서 변경될 때 문제 발생
- React가 잘못된 컴포넌트를 재사용하거나 새로 만들게 됨
- key를 안 쓰는 것과 key={index}는 동일
- key를 안 쓰면 index가 자동으로 주입
key props를 설정하지 않아 발생하는 문제 예시
✅ 문제 상황 이해하기
- 기존의 key값으로 들어간 index로 리렌더링 간 컴포넌트를 기억함
- 0은 Apple, 1은 Banana, 2는 Cherry로 기억
- 맨앞에 “Kiwi”가 추가되어 items의 상태는 변경되었는데, 렌더 단계에서 변경되지 않은 것으로 판단
- 렌더 단계에서는 key, type, props로 변경이 필요한 컴포넌트를 체크 → 모두 같다 → pass
- → state가 브라우저에 반영되지 않음 (커밋 단계 생략)
- items 리스트 렌더링할 때 idx 0, 1, 2는 변화 없으므로 Apple, Banana, Cherry가 DOM에 그려지고, items의 마지막 요소인 Cherry가 idx 3 요소로 들어옴 → Apple - Banana - Cherry - Cherry
💻 동작 코드
import { useState } from "react";
export default function App() {
const [items, setItems] = useState([
{ id: 1, name: "🍎 Apple" },
{ id: 2, name: "🍌 Banana" },
{ id: 3, name: "🍒 Cherry" },
]);
const handleAdd = () => {
const newId = Math.max(...items.map((item) => item.id)) + 1;
const newItem = { id: newId, name: `🥝 Kiwi ${newId}` };
setItems([newItem, ...items]);
};
return (
<div style=>
<h3>✅ ID를 key로 사용한 안전한 리스트</h3>
<button onClick={handleAdd}>맨 앞에 과일 추가</button>
<ul>
{items.map((item, idx) => (
// idx를 key로 할 경우 문제 발생
<li key={item.id}>
<input defaultValue={item.name} />
</li>
))}
</ul>
</div>
);
}
댓글남기기