정답: 알파벳 A
, B
, C
, D
, D
가 보인다.
A
B
C
D
key
에 index
를 넣을 경우 의도치 않은 동작이 발생할 수 있다.
커밋 단계에서 리액트는 이전 버전과 다음 버전을 관찰한 뒤 변화가 있을 때만 DOM 노드를 변경한다고 했다.
위와 같이 <ul>
태그 안에 세 번째 <li>
노드가 생긴 상황을 생각하자. 리액트는 두 리스트를 비교하여 어떤 변화가 생겼는지 파악한다.
<ul>
태그의 첫 번째 자식은 동일하다. 아무 일도 일어나지 않는다.<ul>
태그의 두 번째 자식은 동일하다. 아무 일도 일어나지 않는다.- 그런데
<ul>
태그에 원래 없던 세 번째 자식이 추가 되었다. 리액트는 DOM에 해당 요소를 추가한다.
이렇게 최소한의 DOM 변경을 통해 브라우저의 연산을 줄일 수 있다. 그런데, 만약 마지막이 아닌 첫 번째 자리에 새로운 원소가 생기면 어떻게 될까?
<ul>
태그의 첫 번째 자식은 내용이 바뀌었다 (1
→3
). DOM에 업데이트가 일어난다.<ul>
태그의 두 번째 자식은 내용이 바뀌었다 (2
→1
). DOM에 업데이트가 일어난다.- 그런데
<ul>
태그에 원래 없던 세 번째 자식이 추가 되었다. 리액트는 DOM에 해당 요소를 추가한다.
결국 리액트는 모든 요소를 DOM에서 업데이트 하므로 낭비가 발생하게 된다. 리액트에게 어떤 요소가 동일한 것인지를 알려줄 수는 없을까? 이때 사용할 수 있는 것이 바로 key
속성이다.
위와 같이 코드를 작성하게 되면, 리액트는 자동으로 key
의 값을 참고하여
key
가1
,2
로 동일한<li>
는 업데이트하지 않고,- 새로 생긴
<li>
만 DOM에 해당 요소를 추가한다.
따라서 업데이트에 소모되는 자원을 아낄 수 있는 것이다.
이제 index
를 key
로 사용했을 때 왜 문제가 생기는지 알 수 있다. 리액트는 개발자를 전적으로 믿고, key
가 변하지않으면 상태가 변하지 않는다고 판단한다. 이는 성능 최적화를 위한 조치이지만, 각 요소의 상태가 변할 경우에는 의도한 결과가 나오지 않을 수 있다. 이번 문제의 코드가 정확히 그런 경우이다. 리스트의 가장 앞에 새로운 원소가 추가되었지만 상태는 변하지 않아 알파벳 E
가 보이지 않는다. 이 문제를 해결하기 위해서는 다음과 같이 unique한 key를 제공해주면 된다. 그러면 의도한대로 잘 작동하는 것을 볼 수 있다.
A
B
C
D