본문 바로가기

Front-End: Web/React.js

[React] 엘리먼트 리스트에 key가 왜 필요해?

반응형

key

  • 엘리먼트 리스트를 만들 때 포함해야 하는 특수한 문자열 attribute.
  • **React가 어떤 항목을 변경, 추가, 삭제할지 식별하는 것을 돕는다.**

 

자식에 대한 재귀적 처리

React는 기본적으로 기존 트리와 이후 트리의 자식들을 동시에 보고, 차이점이 있으면 DOM을 변경한다.

예로 들어서 자식의 끝에 엘리먼트를 추가하면 변경은 잘 작동한다.

<ul>
  <li>first</li>
  <li>second</li>
</ul>

<ul>
  <li>first</li>
  <li>second</li>
  <li>third</li>
</ul>

React는 두 트리에서 <code><li>first</li></code> 가 일치하는 것을 확인하고, <code><li>second</li></code>가 일치하는 것을 확인한다. 그리고 마지막을 <code><li>third</li></code>를 트리에 추가한다.

 

문제점

하지만 위와 같이 단순히 리스트 맨 아래에 추가하면 괜찮지만, 리스트 맨 앞에 엘리먼트를 추가하는 경우에는 성능이 좋지 않다. 예를 들면 다음과 같은 아래 두 트리 변환은 형편없이 작동한다.

<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>` 종속 트리를 그대로 유지하고 있는데에도 React는 **모든 자식을 변경**한다. 이러한 비효율은 문제가 될 수 있다.

 

문제점 해결: Keys

이 문제를 해결하기 위해서 React는 key 속성을 지원한다. 자식들이 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' key를 가진 엘리먼트를 새로 추가하고, '2015', '2016' key를 가진 엘리먼트는 그냥 이동만 하면 된다는 걸 알게 된다.

 

key값 정하기

리스트의 다른 항목들 사이에서 해당 항목을 고유하게 식별할 수 있는 문자열을 사용하는 것이 가장 좋다. 그래서 대부분 데이터의 ID를 key로 사용한다.

<li key={item.id}>{item.name}</li>

근데 만~~약에 유닉한 데이터를 가지고 있지 않다면?

  1. 데이터 구조에 ID라는 속성을 추가해서 key 생성하기
  2. 데이터 일부에 해시를 적용해서 key 생성하기

**key는 전역에서 유일할 필요가 없다. 오로지 형제 사이에서만 유일하기만 하면 된다!**

 

map의 index를 key로 주면 안되는 이유는?

만약 데이터에 안정적인 ID가 없다면, 최후의 수단으로 index를 key로 사용할 순 있다.

하지만 항목의 순서가 바뀔 수 있는 경우(재배열)에는 key에 인덱스를 사용하면 비효율적으로 동작하고 컴포넌트의 state 관련 문제가 발생할 수 있다.

컴포넌트 인스턴스는 key를 기반으로 갱신되고 재사용되는데, 인덱스를 key로 사용하면 항목의 순서가 바뀌었을 때 key 또한 바뀔 것이기 때문이다. 그래서 결론적으로 모든 자식들이 재렌더링될 수도 있고(겁나 비효율적임), 컴포넌트의 state가 엉망이 되거나 의도하지 않는 방식으로 바뀔 수도 있다.

 

 

 


참고 자료

 

반응형