리액트는 가상DOM을 사용하여 높은 효율을 자랑한다. 그러므로 기본적으로 변경이 필요한 부분만 변경할 수 있을 때 그 진가를 발휘한다고 볼 수 있다.
그런데 만약 여러개로 나열된 형제노드에서 어떤 항목이 추가되거나 변경, 삭제 된다면 리액트는 그 변화를 어떻게 인지할 수 있을까?
<ul>
<li>Duke</li>
<li>Villanova</li>
</ul>
<ul>
<li>Connecticut</li>
<li>Duke</li>
<li>Villanova</li>
</ul>
예를 들어 위의 리스트에서 아래 리스트로 변경한다고 했을 때 리액트는 <li>Duke</li>
와 <li>Villanova</li>
종속트리를 유지하는 대신 모든 자식들을 리렌더링하게 된다. 즉, 리액트가 변화를 식별할 수 있다면 <li>Conneticut</li>
만 추가하면 될 것을, 그렇지 못하여 데이터를 싹 다 바꾸는 것이다.
이런식으로 리액트는 state를 사용해 변경 사항이 있는 부분을 리렌더링 하는데 만약 불필요한 리렌더링이 자주 발생하게 되면 리액트를 활용하는 그 가치가 현저히 줄어들게 된다!!
그리하여 고안해낸 것이 있으니, 바로 키이다.
자식들이 key를 가지고 있다면, React는 key를 통해 기존 트리와 이후 트리의 자식들이 일치하는지 확인한다. 예를 들어, 위 비효율적인 예시에 key를 추가하여 트리의 변환 작업이 효율적으로 수행되도록 수정할 수 있다.
<ul>
<li key="2015">Duke</li>
<li key="2016">Villanova</li>
</ul>
<ul>
<li key="2014">Connecticut</li>
<li key="2015">Duke</li>
<li key="2016">Villanova</li>
</ul>
이제 리액트는 2014라는 키를 가진 엘리먼트가 새로추가 되었고, 2015, 2016을 키로 가진 엘리먼트는 그저 이동만 하면 된다는걸 알게 되었다.
리액트에서 키는 어떤 항목을 변경, 추가 또는 삭제할지 식별하는 것을 돕는다. 키는 엘리먼트에 안정적인 고유성을 부여하기 위해 배열내부의 엘리먼트에 지정해야한다.
const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map((number) =>
<li key={number.toString()}>
{number}
</li>
);
키를 선택하는 가장 좋은 방법은 리스트의 다른 항목들 사이에서 해당 항목을 고유하게 식별할 수 있는 문자열을 사용하는 것이다. 대부분 데이터의 아이디를 키로 사용한다.
//데이터의 아이디를 키값으로 사용하기
const todoItems = todos.map((todo) =>
<li key={todo.id}>
{todo.text}
</li>
);
렌더링 한 항목에 대한 안정적인 아이디가 없다면 최후의 수단으로 항목의 인덱스를 키로 사용할 수 있다.
//권장되지는 않지만 인덱스를 키로 사용하기
const todoItems = todos.map((todo, index) =>
// Only do this if items have no stable IDs
<li key={index}>
{todo.text}
</li>
);
항목의 순서가 바뀔 수 있는 경우, 키에 인덱스를 사용하는 건 권장되지 않는다고 한다. 이로 인해서 성능이 저하되거나 컴포넌트의 state와 관련된 문제가 발생할 수 있어서이다.
만약 리스트 항목에 명시적으로 키를 지정하지 않으면 리액트는 기본적으로 인덱스를 키로 사용한다.
있다.
보통 map()함수 내부에 있는 엘리먼트에 key를 넣어주는게 좋다고 한다.
function ListItem(props) {
const value = props.value;
return (
// 틀렸습니다! 여기에는 key를 지정할 필요가 없습니다.
<li key={value.toString()}>
{value}
</li>
);
}
function NumberList(props) {
const numbers = props.numbers;
const listItems = numbers.map((number) =>
// 틀렸습니다! 여기에 key를 지정해야 합니다.
<ListItem value={number} />
);
return (
<ul>
{listItems}
</ul>
);
}
const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
<NumberList numbers={numbers} />,
document.getElementById('root')
);
Key는 배열 안에서 형제 사이에서 고유해야 하고 전체 범위에서 고유할 필요는 없다. 두 개의 다른 배열을 만들 때 동일한 key를 사용할 수 있다.