리액트에서 key의 역할

·
6 min read

리액트에서 동적인 배열을 렌더링해야 할 때, 자바스크립트 배열의 내장함수 map()을 사용하여 일반 데이터 배열을 리액트 엘리먼트로 이루어진 배열로 변환해 줍니다.

하지만 그냥 map()을 사용하여 배열을 렌더링한 후 콘솔을 열어보면 다음과 같은 에러를 볼 수 있습니다. 리액트에서 배열을 렌더링할 때는 key라는 props를 설정해야 합니다.

Key

key는 리액트가 어떤 항목을 변경, 추가 또는 삭제할지 식별할 것을 돕습니다. key는 엘리먼트에 안정적인 고유성을 부여하기 위해 배열 내부의 엘리먼트에 지정해야 합니다.

예를 들어서 다음과 같이 배열을 렌더링한다고 가정해 보겠습니다.

const array = ['a', 'b', 'c', 'd']

array.map(item => <div>{item}</div>)
const array = ['a', 'b', 'c', 'd']

array.map(item => <div>{item}</div>)

위 배열의 b와 c 사이에 z를 삽입하게 된다면, 리렌더링을 하게 될 때 <div>b</div><div>c</div> 사이에 새 div 태그를 삽입하는 것이 아니라, 기존의 c가 z로 바뀌고, d는 c로 바뀌고 맨 마지막에 d가 새로 삽입됩니다.

그다음 a를 제거하게 된다면, 기존의 a가 b로 바뀌고, b는 z로 바뀌고, z는 c로 바뀌고, c는 d로 바뀌고, 맨 마지막에 있는 d가 제거됩니다.

이처럼 key가 없다면 Virtual DOM을 비교하는 과정에서 리스트를 순차적으로 비교하면서 변화를 감지합니다. 즉, key가 없는 경우 변경이 필요하지 않은 리스트의 요소까지 변경이 일어나게 되므로 비효율적이라고 할 수 있습니다.

이런 부분을 개선하기 위해서 key를 사용할 수 있습니다. 이번엔 객체에 key로 사용할 수 있는 고유한 값(id)을 지닌 배열이 있고, 배열의 id를 key로 사용하여 렌더링한다고 가정하겠습니다.

const array = [
{
id: 0,
text: 'a',
},
{
id: 1,
text: 'b',
},
{
id: 2,
text: 'c',
},
{
id: 3,
text: 'd',
},
]

array.map(item => <div key={item.id}>{item.text}</div>)
const array = [
{
id: 0,
text: 'a',
},
{
id: 1,
text: 'b',
},
{
id: 2,
text: 'c',
},
{
id: 3,
text: 'd',
},
]

array.map(item => <div key={item.id}>{item.text}</div>)

이처럼 리스트를 렌더링할 때 고유한 key 값이 있다면 리스트가 업데이트될 때마다 변경되지 않은 값들은 그대로 두고, 원하는 값을 삽입하거나 삭제할 수 있습니다.

key의 올바른 사용법

key를 선택하는 가장 좋은 방법은 리스트의 다른 항목들 사이에서 해당 항목을 고유하게 식별할 수 있는 문자열을 사용하는 것입니다. 고유한 값은 배열이 다시 렌더링 되는 과정에서 리스트 항목의 순서를 보장할 수 있기 때문입니다. 대부분의 경우 데이터의 ID를 key로 사용합니다. 만약 중복되는 key가 있을 때는 렌더링 시에 오류메시지가 콘솔에 나타나게 되며, 업데이트가 제대로 이루어지지 않게 됩니다

key로서의 index

렌더링 한 항목에 대한 안정적인 ID가 없다면 최후의 수단으로 항목의 index를 key로 사용할 수 있습니다. 하지만 항목의 순서가 바뀔 수 있는 경우 key에 index를 사용하는 것은 권장하지 않습니다.

key는 리액트가 DOM 요소를 식별하는 데 사용하는 유일한 값입니다. 항목을 추가 또는 삭제할 경우, 각 항목의 index 또한 재배치됩니다. 그 결과 key를 변경시켜 렌더링 성능이 저하할 우려가 있습니다.

하지만 다음과 같은 경우, key로 index를 사용할 수 있습니다.

  • 리스트와 항목이 고정되어, 다시 계산되거나 수정되지 않는다.
  • 리스트의 아이템에 id가 없다.
  • 리스트가 재배치되거나 필터 되지 않는다.

참고 자료