React 리스트 렌더링 — .map() · key
배열 100개를 JSX 100개로 한 줄에. key prop 의 진짜 의미까지.
실전 React 앱에서 가장 자주 나오는 패턴 — "배열 데이터를 받아 UI 항목 여러 개로 그리기". 사용자 목록·상품 카탈로그·댓글·알림 — 전부 같은 모양. JS 의 .map() 메서드와 JSX 가 만나는 지점.
이번 9편은 .map() 기본 + key prop 의 진짜 역할 (대부분 잘못 설명됨) + index 를 key 로 쓰면 일어나는 사고 + 필터·정렬 패턴까지.
1. .map() — 배열을 JSX 배열로
JSX 중괄호 안에 JSX 요소의 배열 을 넣으면 React 가 순서대로 그린다.
핵심 — .map() 의 콜백이 JSX 를 return. 각 항목마다 컴포넌트 하나가 생성. 화살표 함수의 본문이 한 줄이면 괄호로 감싸 암묵적 return, 여러 줄이면 중괄호 + 명시적 return.
2. key prop — "성능 최적화" 가 아니다
거의 모든 한국 튜토리얼이 "key 는 성능 최적화용" 이라고 설명. 절반만 맞다. 진짜 역할은 React 가 "어느 항목이 누구인지" 추적하기 위함 — 항목이 추가·삭제·재배치될 때 어떤 DOM 노드를 재사용하고 어떤 걸 새로 만들지 결정.
key 가 없으면 React 가 "이 항목이 이전 렌더의 그 항목인지" 알 수 없다. 100개 리스트에서 첫 항목 삭제하면 — React 입장에선 100개를 새로 그리는 것과 같음. key 가 있으면 "첫 항목만 사라지고 나머지 99개는 그대로" 인 걸 안다.
3. index 를 key 로 쓰면 안 되는 진짜 이유
가장 흔한 패턴 — 데이터에 id 가 없어서 .map((item, i) => ... key={i}) 처럼 index 사용. 정적 리스트면 OK, 항목이 추가·삭제·재정렬되는 순간 버그 폭탄.
왜냐하면 React 가 "key=0 이 빵, key=1 이 커피" 로 기억. 삭제 후엔 "key=0 이 빵→ 우유 자리에 빵을 그림" 이 아니라 "key=0 자리에 새 데이터 빵을 끼움" 인데 input 의 internal state (사용자가 입력한 '식빵') 가 첫 자리에 남아있어 어긋남.
해결책 — 안정적 id. 데이터 생성 시 crypto.randomUUID() 또는 Date.now() 같은 고유값 박기:
4. 필터·정렬 — .map() 앞에 체이닝
JSX 중괄호는 JS 표현식이라 메서드 체이닝 자유롭게. 필터 후 정렬 후 렌더.
이 한 줄이 SQL 의 SELECT WHERE ORDER BY 와 같은 일을 한다. 다만 — .sort() 는 원본 배열을 변경한다. props 로 받은 배열을 직접 sort 하면 React 의 immutability 원칙 위반. [...products].sort(...) 처럼 spread 로 복사본을 먼저 만들고 정렬해야 안전.
이 패턴이 손에 잡히면 동적 UI 의 99% 가 가능. 10편에서 Form — controlled vs uncontrolled 입력 관리 + 다중 input 처리로 마무리.
다음 글
React 교재 10편 — Form 다루기. controlled vs uncontrolled, 다중 input useState 패턴, 제출 처리.