Map에 Key가 필요한 이유

jh_leitmotif·2021년 12월 17일
1

Frontend 개인 공부

목록 보기
15/24

Why map needs key?

프로젝트를 진행하다보면 실시간으로 변경되는 데이터가 있습니다.

가장 쉬운 예시로는 댓글 달기 같은 것이 있고

노션이나 구글 docs 같이 한 문서를 동시에 여러 사람이 수정한다거나...

하는 경우가 있습니다.

단적인 예시코드를 들어보겠습니다.

위의 코드는 받아온 댓글데이터에 대해 map 함수를 통해서

각각의 컴포넌트를 렌더링해주는데, 무언가 빠진 것이 있는지 공포의 노란 줄이 쫙쫙 그어져있습니다.

커서를 가져다대보니, 'key' prop이 없다는 이야기가 나오고

알려준대로 key를 넣으니 문제가 해결되었습니다.

왜 Key가 필요한가? 에 대해서는 React의 렌더링 방식을 짚어볼 필요가 있습니다.

How React works

참고 링크 : https://velog.io/@leitmotif/React-%EB%8F%99%EC%9E%91-%EC%9B%90%EB%A6%AC

당장 제가 일전에 썼던 React의 동작 원리에 그 정답이 있습니다.

React는 state의 Update 여부에 따라 렌더링이 되지 않거나, 되곤 합니다.

변경 사항이 있을 때마다 DOM 조작이 일어나는 것과 다르게

React는 변경 전, 후의 Virtual DOM을 서로 비교하여

실제 변경된 부분만 DOM을 업데이트하는 최소한의 조작성을 보입니다.

여기에 Diffing Algorithm이 적용됩니다.

Diffing Algorithm

React는 상태 변화를 비교하기 위해 Diffing Algorithm을 적용하는데,

간략히 정리하면 다음과 같습니다.

  1. Root에 새로 변경점이 있다면 새로 만들고 덧씌운다.
  2. Root가 같다면 자식 노드를 비교하여 변경점을 확인하고, 있다면 기존의 것을 unmount하고 변경된 것을 mount합니다.
  3. 자식 노드도 같다면 Attribute의 변경점을 확인합니다.
<ul>
  <li>a</li>
  <li>b</li>
  <li>c</li>
</ul>

각각에 대해서 위의 코드를 기준으로 설명합니다.

1. root 부분이 변경되는 경우!

<ol>
  <li>a</li>
  <li>b</li>
  <li>c</li>
</ol>

root인 ul이 ol로 변경되었기 때문에

자식 노드가 어떤지 신경쓰지 않고 새로 덧씌웁니다.

2. 자식노드가 변경되는 경우!

<ul>
  <li>a</li>
  <li>b</li>
  <li>c</li>
  <li>new</li> // Here is a new li element!
</ul>

마지막에 li element가 들어왔습니다.

변경 이전, a~c list element는 그대로이기에 변경점을 찾지 못하다가

마지막 new에서 변경점이 인식되므로 단순히 ul에 li를 추가하는 것만으로

DOM 조작이 진행됩니다.

3. Attribute가 변경된 경우!

<ul>
  <li name='a'>a</li>
  <li>b</li>
  <li>c</li>
</ul>
<ul>
  <li name='new'>a</li>
  <li>b</li>
  <li>c</li>
</ul>

위와 같이 DOM의 구조는 같지만

어떠한 element의 Attribute만 변경되었다면 변경 전/후의 attr을 비교해

변경된 부분만 업데이트합니다.

reason of use Key props

위의 Diffing 이야기에서, Key를 쓰는 것은 2번에 해당됩니다.

React는 변경 전/후의 Virtual DOM을 순회하고 변경점이 있다면 그 부분만 업데이트합니다.

그런데 여기서,

위의 경우 React는 생각합니다.

1. 기존 li는 a! 어? new로 변경되었으니 새로 업데이트!
2. 기존 li는 b! 어? a로 변경되었으니...
3. 기존 li는 c! 어? b로 변경되었으니...
4. 어? c li element가 있네? 추가!

그저 맨 위에 new li element가 추가되었을 뿐인데, DOM을 순회하며 하나하나 변경점을 찾아다니는 비효율적인 동작이 발생합니다.

여기서 React는 Key prop을 통해 단번에 해결했습니다.

이렇게 key를 색인 용도로 넣어주면

DOM을 순회하기 전에 먼저 기존의 key들과 다른 key가 있는지 확인하기만 하면 됩니다.

다시 앞으로 돌아가서, 댓글은 실시간적인 특성을 가집니다.

추가되는 댓글은 말미에 들어가겠지만, 삭제의 경우 순서와 상관없이

불특성한 요소가 삭제되기 마련입니다.

그러므로 key 값을 색인해주어야 불필요한 비교 작업을 하지 않고

효율적인 DOM 업데이트를 실현할 수 있는 것입니다.


profile
Define the undefined.

0개의 댓글