2026. 7. 1.
React key 경고, AI 코딩 초보가 3분 만에 리스트 값 섞임을 막는 5칸
AI가 만든 React 리스트에서 key prop 경고가 뜨거나 삭제 후 입력값이 다른 줄로 이동한다면 전체 재작성보다 map 위치, 고유 id, index 위험, 정렬 테스트를 먼저 확인해야 합니다.

AI가 만들어 준 할 일 목록, 장바구니, 댓글 리스트가 처음에는 잘 보이는데 콘솔에 Each child in a list should have a unique "key" prop 경고가 뜰 때가 있습니다. 더 불안한 장면은 항목을 삭제하거나 정렬한 뒤입니다. 방금 입력한 값이 다른 줄로 이동하거나, 체크 표시가 엉뚱한 항목에 붙어 보입니다. 이때 전체 컴포넌트를 다시 만들기 전에 **리스트 항목의 신분증 역할을 하는 key**부터 확인해야 합니다.
react.dev의 Rendering Lists 문서는 map() 안에서 바로 반환되는 JSX에는 key가 필요하고, key가 React에게 각 컴포넌트가 배열의 어느 항목에 해당하는지 알려 준다고 설명합니다. 같은 문서는 항목이 정렬, 추가, 삭제될 수 있을 때 key가 특히 중요하다고 안내합니다. Preserving and Resetting State 문서는 React가 기본적으로 렌더 트리의 위치를 기준으로 상태를 보존하고, key가 그 위치 판단에 들어갈 수 있다고 설명합니다. 그래서 이 문제는 단순한 콘솔 경고가 아니라 입력값과 선택 상태가 어느 항목에 붙을지의 문제입니다.
30초 안에 경고 줄과 map 위치를 같이 찾습니다
먼저 브라우저 콘솔에서 경고 문장을 그대로 확인합니다.
Warning: Each child in a list should have a unique "key" prop.
이 문장은 보통 화면이 깨졌다는 뜻보다, 반복 렌더링된 자식에게 안정적인 이름표가 없다는 뜻에 가깝습니다. AI에게 바로 "고쳐 줘"라고 말하면 전체 리스트 구조를 바꿀 수 있으니, 먼저 문제가 되는 map()을 찾습니다.
{items.map((item) => (
<li>{item.name}</li>
))}
위 코드처럼 map()이 있고, 그 안에서 반환되는 가장 바깥 JSX에 key가 없다면 첫 번째 수정 지점입니다. 바깥 요소가 li이면 li에 붙이고, Card 컴포넌트를 바로 반환한다면 Card에 붙입니다.
{items.map((item) => (
<li key={item.id}>{item.name}</li>
))}
여기서 목표는 경고를 없애는 것이 전부가 아닙니다. React가 각 줄을 같은 항목으로 계속 알아보게 만드는 것이 목표입니다.
1분 안에 key 후보를 item.id에서 먼저 찾습니다
가장 먼저 찾을 값은 서버, 데이터베이스, API 응답, 로컬 데이터에 이미 들어 있는 고유 id입니다.
const items = [
{ id: "todo-1", name: "회원가입 화면 만들기" },
{ id: "todo-2", name: "버튼 클릭 연결하기" },
{ id: "todo-3", name: "배포 오류 확인하기" }
];
export default function TodoList() {
return (
<ul>
{items.map((item) => (
<li key={item.id}>{item.name}</li>
))}
</ul>
);
}
React 공식 문서는 key를 렌더링 중에 새로 만들기보다 데이터에 포함시키라고 안내합니다. 그래서 crypto.randomUUID(), Date.now(), Math.random()을 JSX 안에서 바로 호출하는 식은 피해야 합니다. 매번 다른 key가 생기면 React가 이전 항목과 새 항목을 맞추지 못하고, 내부 상태나 DOM을 다시 만들 수 있습니다.
AI에게는 이렇게 물어보는 편이 안전합니다.
이 React 리스트에서 key prop 경고가 납니다.
전체 컴포넌트를 다시 쓰지 말고, items 데이터 안에 이미 있는 안정적인 id를 찾아 key로 써 주세요.
렌더링 중 Math.random(), Date.now(), crypto.randomUUID()를 새로 호출하지 마세요.
수정 파일과 수정 줄만 설명해 주세요.
이 요청은 AI가 임시로 아무 key나 붙이는 일을 줄입니다. key는 화면 순서가 아니라 항목 자체를 따라가야 합니다.
2분 안에 index key가 위험한 리스트인지 판단합니다
AI가 다음처럼 고쳐 주는 경우가 많습니다.
{items.map((item, index) => (
<li key={index}>{item.name}</li>
))}
경고는 사라질 수 있지만, 이 코드가 항상 안전한 것은 아닙니다. 순서가 절대 바뀌지 않고, 항목이 추가되거나 삭제되지 않으며, 각 줄 안에 입력값이나 선택 상태가 없다면 당장 문제가 드러나지 않을 수 있습니다. 하지만 초보자가 만드는 실제 화면은 대개 검색, 정렬, 삭제, 체크, 입력을 곧 붙입니다.
다음 중 하나라도 있으면 index를 key로 쓰지 않는 쪽으로 봅니다.
| 상황 | 왜 위험한가 |
|---|---|
| 삭제 버튼이 있다 | 두 번째 항목을 지우면 세 번째 항목이 두 번째 위치로 올라옵니다. |
| 정렬 버튼이 있다 | 같은 항목이 다른 위치로 이동합니다. |
| 검색이나 필터가 있다 | 화면에 남는 항목의 순서와 개수가 바뀝니다. |
| 줄마다 input이 있다 | 입력 상태가 위치에 붙어 다른 항목처럼 보일 수 있습니다. |
| 체크박스나 선택 표시가 있다 | 선택 상태가 항목이 아니라 줄 번호를 따라갈 수 있습니다. |
Preserving and Resetting State 문서의 핵심은 상태가 컴포넌트의 위치와 연결된다는 점입니다. key는 그 위치 판단에 영향을 줍니다. 그래서 index key는 "두 번째 줄"이라는 위치를 항목의 정체성처럼 쓰는 셈이 됩니다. 항목이 움직이는 리스트라면 안정적인 item id를 key로 쓰는 것이 기본값입니다.
3분 안에 삭제와 정렬 테스트로 확인합니다
수정 후에는 화면을 보는 것만으로 끝내지 않습니다. 리스트가 섞이는 문제는 처음 렌더링이 아니라 변화 후에 드러납니다. 아래 5칸을 채우면서 확인합니다.
1. 콘솔 경고 줄:
2. 문제가 되는 map 위치:
3. 사용할 고유 id:
4. index key를 쓰면 위험한 이유:
5. 삭제/정렬/필터 후 값이 그대로 붙는지:
간단한 테스트는 이 순서로 합니다.
- 두 번째 항목의 입력칸에 값을 적습니다.
- 첫 번째 항목을 삭제합니다.
- 방금 적은 값이 같은 항목에 남아 있는지 봅니다.
- 이름순 정렬을 실행합니다.
- 체크 표시와 입력값이 항목을 따라가는지 다시 봅니다.
이 테스트에서 값이 다른 줄로 이동하면 key가 아직 위치처럼 쓰이고 있을 가능성이 큽니다. 이때 AI에게는 전체 재작성을 맡기지 말고, 증상과 테스트 결과를 함께 줍니다.
React 리스트에서 key 경고를 고쳤지만 삭제 후 입력값이 다른 항목으로 이동합니다.
현재 코드는 key={index}를 사용합니다.
이 리스트는 삭제와 정렬이 가능하고, 각 줄에 input 상태가 있습니다.
items 안의 안정적인 id를 key로 사용하도록 최소 범위로 수정해 주세요.
수정 후 어떤 테스트로 확인해야 하는지도 3개만 적어 주세요.
이 문장에는 AI가 판단해야 할 정보가 들어 있습니다. index를 쓰고 있다는 점, 삭제와 정렬이 있다는 점, 줄마다 상태가 있다는 점입니다. 이 세 가지가 들어가면 AI가 단순히 경고만 없애는 대신 상태가 섞이는 이유까지 반영할 가능성이 높아집니다.
key가 컴포넌트 props로 들어온다고 착각하지 않습니다
초보자가 자주 놓치는 지점이 하나 더 있습니다. key는 React가 쓰는 힌트이지, 자식 컴포넌트가 일반 props처럼 받는 값이 아닙니다. 자식 컴포넌트 안에서도 id가 필요하다면 별도 prop으로 넘깁니다.
{items.map((item) => (
<TodoRow key={item.id} itemId={item.id} name={item.name} />
))}
function TodoRow({ itemId, name }: { itemId: string; name: string }) {
return (
<li data-item-id={itemId}>
{name}
</li>
);
}
key={item.id}만 붙였는데 TodoRow 안에서 props.key를 읽으려 하면 원하는 값이 나오지 않습니다. id가 로직에 필요하면 itemId={item.id}처럼 따로 넘겨야 합니다. 이 구분을 알면 AI가 만든 코드에서 "key는 있는데 왜 내부에서 id를 못 읽지?"라는 두 번째 혼란을 줄일 수 있습니다.
오늘은 경고 제거보다 항목 정체성을 먼저 고정합니다
React key 경고는 화면이 바로 멈추는 오류가 아니라서 지나치기 쉽습니다. 하지만 리스트에 삭제, 정렬, 필터, 입력, 체크 상태가 붙는 순간 작은 경고가 실제 버그로 바뀔 수 있습니다. 오늘 확인할 순서는 단순합니다.
경고 줄을 본다.
map 위치를 찾는다.
item.id 같은 안정적인 key를 찾는다.
index key가 위험한 리스트인지 판단한다.
삭제와 정렬 후 입력값이 같은 항목에 남는지 테스트한다.
AI 코딩 초보라면 이 5칸만 먼저 채워도 충분합니다. 목표는 React를 전부 다시 배우는 것이 아니라, 지금 섞이는 리스트의 정체성을 고정하는 것입니다. 그 다음 AI에게 "전체 재작성 없이 안정적인 id key로 최소 수정해 달라"고 요청하면 됩니다.
참고 출처
- React Docs, Rendering Lists: https://react.dev/learn/rendering-lists
- React Docs, Preserving and Resetting State: https://react.dev/learn/preserving-and-resetting-state
다음으로 읽을 기사
같은 흐름으로 이어 읽기 좋은 기사만 추려 보여줍니다.
첫 번째 댓글을 남겨보세요
여러분의 생각이 다른 독자에게 도움이 됩니다.
댓글 0
이 글을 읽은 독자들의 생각을 나눠보세요.