리스트와 키
할 일 목록을 만들고 있다고 생각해 봅시다. 각 항목이 고유한 텍스트를 가지고 있고, todo 객체의 배열에서 가져온 것입니다. React에는 배열을 마크업으로 변환하는 특별한 리스트 컴포넌트가 없습니다. 일반 JavaScript의 map을 사용해서 각 항목을 JSX 조각으로 변환하고, React가 결과를 렌더링합니다.
function TodoList({ todos }) {
return (
<ul>
{todos.map(todo => (
<li key={todo.id}>{todo.text}</li>
))}
</ul>
)
}map으로 리스트 렌더링하기
todos 배열은 보통 실제 데이터를 소유하고 있는 부모 컴포넌트에서 prop으로 전달됩니다. todos.map은 배열을 순회하면서 각 todo에 대해 하나의 <li>를 반환합니다. 그 주위의 중괄호는 JSX 요소의 배열을 <ul> 안에 바로 삽입합니다. 단일 표현식을 삽입하는 것과 같은 방식입니다. 각 <li>는 또한 key prop을 가지고 있으며, todo.id로 설정됩니다. 리스트가 제대로 동작하려면 이 부분은 선택사항이 아닙니다. 키를 생략하면 React는 여전히 리스트를 렌더링하지만 콘솔 경고를 남기고, 아래에서 설명하는 재정렬 버그가 리스트가 처음 변할 때 실제 위험이 됩니다.
키는 React가 한 렌더링에서 다음 렌더링으로 리스트 항목을 구분하는 방식입니다. 형제들 사이에서 고유해야 하므로 이 리스트의 두 <li> 요소가 같은 키를 공유할 수 없고, 안정적이어야 합니다. 즉, 같은 todo는 리스트가 다시 렌더링될 때마다 같은 키를 받아야 합니다. todo.id 같은 데이터의 id는 정확히 그러합니다. 배열의 위치가 아니라 todo에 속하므로, 주변 리스트가 변해도 그대로 유지됩니다.
배열 인덱스가 좋지 않은 키인 이유
마지막 점이 배열 인덱스가 좋지 않은 키인 이유입니다. 모든 배열이 이미 가지고 있으므로 그것을 사용하는 것이 유혹적입니다.
{todos.map((todo, index) => (
<li key={index}>{todo.text}</li>
))}리스트가 절대 재정렬되지 않고 항목이 삽입되거나 삭제되지 않는 한 이것은 잘 작동합니다. 그 순간, 인덱스는 이전에 가리키던 항목과 일치하지 않게 됩니다. 첫 번째 todo를 삭제하면 모든 남은 항목이 한 칸씩 올라가므로, React는 같은 키가 다른 todo에 붙어 있는 것을 봅니다. 그 리스트 항목들이 자신의 상태를 가지고 있다면, 편집 중인 체크박스나 누군가 입력 중인 input 같은 경우, 그 상태는 인덱스에 붙어 있게 되고 결국 잘못된 행에 끝나게 됩니다. 인덱스를 정적이고 절대 재정렬되지 않는 리스트의 대체제로 취급하세요. 다른 곳에서는 진짜 id를 사용하세요.
map으로 요소의 리스트로 변환할 때, 각각에 key를 주고, 배열의 위치가 아니라 데이터의 진짜 id를 사용하세요. 키는 React가 렌더링 사이에 어느 요소가 어느 것인지 추적하는 방법이고, 항목에 속하는 id는 리스트가 재정렬되더라도 올바르게 유지됩니다. 다음: 상태. 컴포넌트가 렌더링 사이에 정보를 기억하기 시작합니다.

