리액트에서의 키는 리스트에서 아이템을 구분하기 위한 고유한 문자열을 말하며, key
속성에는 보통 데이터 베이스 상의 유니크한 값(Id)을 부여해준다. 키는 전역적으로 유일할 필요는 없고, 형제 엘리먼트(같은 리스트) 사이에서만 고유한 값이면 된다.
자식 노드들이 이 key
를 가지고 있다면, React는 그 key를 이용해 기존 트리의 자식과 새로운 트리의 자식이 일치하는지 아닌지 확인할 수 있다.
아래의 예제에서 React는 key 속성을 통해 ‘2014’
라는 자식 엘리먼트가 새롭게 생겼고, ‘2015’
, ‘2016’
키를 가진 엘리먼트는 단지 위치만 이동했다는 걸 알게 된다. 따라서 React는 기존의 동작 방식대로 다른 자식 엘리먼트는 변경하지 않고 추가된 엘리먼트만 변경한다.
<ul>
<li key="2015">Duke</li>
<li key="2016">Villanova</li>
</ul>
<!-- key가 2014인 자식 엘리먼트를 처음에 추가한다. -->
<ul>
<li key="2014">Connecticut</li>
<li key="2015">Duke</li>
<li key="2016">Villanova</li>
</ul>
const numbers = [1, 2, 3, 4, 5];
function listItems() {
return (
<ul>
{numbers.map((value) => {
<li key={value.toString()}>{value}</li>
})}
</ul>
);
}
function todoItmes() {
return (
<ul>
{todos.map((value) => {
<li key={value.id}>{value.text}</li>
})}
</ul>
);
}
아래는 키값으로 index를 사용한 경우다. 이 방법은 map()
함수에서 두 번째 파라미터로 제공해 주는 인덱스 값을 키값으로 사용한다.
인덱스 값도 고유한 값이기 때문에 키값으로 사용해도 되지만, 배열이 다르게 정렬될 경우가 생긴다면 키값으로 사용하는 것을 권장하지 않는다.
왜냐하면 배열이 다르게 정렬되어도 인덱스는 그대로 유지되기 때문이다. 인덱스는 그대로지만 그 요소가 바뀌어버린다면 React는 배열의 전체가 바뀌었다고 받아들일 것이고, 기존의 DOM 트리를 버리고 새로운 DOM 트리를 구축해버리기 때문에 비효율적으로 동작하는 것이다.
따라서 index를 키값으로 사용하는 것은 아이템들의 고유한 id가 없을 경우에만 사용하는 것이 좋다.
function todoItmes() {
return (
<ul>
{todos.map((value, index) => {
<li key={index}>{value.text}</li>
})}
</ul>
);
}
키값으로 index를 사용하면 안 되는 이유