가상 돔(Virtual DOM)은 이전 버전의 가상 돔과 새로운 버전의 가상 돔을 비교하는 과정에서 ‘비교 알고리즘’을 따라 동작합니다. 이번 포스팅에서는 비교 알고리즘의 간단한 동작 원리를 살펴보도록 하겠습니다.
key
prop을 주는 것이 좋습니다.아래는 가상 돔 비교 알고리즘의 동작을 코드 예시를 통해 확인하는 코드입니다.
<div>
<Counter />
</div>
--------------------------------------------------------
<span>
<Counter />
</span>
두 Counter 엘리먼트의 루트 엘리먼트는 각각 div와 span으로 타입이 다릅니다.
이 경우, 기존의 트리를 버리고 완전히 새로운 트리를 구축합니다.
// before
<div className="berfore" title="vdom" style="{{backgroundColor: 'red', height: '10px'}}">
<a>a1</a>
<a>a2</a>
</div>
--------------------------------------------------------
// after
<div className="after" title="vdom" style="{{backgroundColor: 'blue', height: '10px'}}">
<a>a0</a>
<a>a1</a>
<a>a2</a>
</div>
두 div 엘리먼트는 루트 엘리먼트가 div로 타입이 동일합니다.
이 경우, 동일한 속성은 유지하고 변경된 속성들만 갱신합니다.
즉, 루트 엘리먼트는 className
과 style 속성 중 backgroundColor
속성만을 수정합니다.
이제 DOM 노드의 자식들을 재귀적으로 처리하며 비교해보겠습니다.
코드를 보았을 때, 자식노드 a1과 a2가 일치하고, 새롭게 a0이 추가된 것을 알 수 있습니다.
그러나 이 경우, 리액트는 예상과 다르게 작동합니다.
자식노드 a1과 a2도 변경되었다고 판단해 결과적으로 모든 자식이 변경됩니다.
이러한 문제를 해결하기 위해 key
prop을 활용해 코드를 수정해보겠습니다.
// before
<div className="berfore" title="vdom" style="{{backgroundColor: 'red', height: '10px'}}">
<a key='01'>a1</a>
<a key='02'>a2</a>
</div>
--------------------------------------------------------
// after
<div className="after" title="vdom" style="{{backgroundColor: 'blue', height: '10px'}}">
<a key='00'>a0</a>
<a key='01'>a1</a>
<a key='02'>a2</a>
</div>
리액트는 ‘00’ key를 가진 엘리먼트가 추가되었고, ‘01’과 ‘02’ key를 가진 엘리먼트는 위치만을 이동하면 된다고 판단합니다.
이렇게 자식 노드 간의 비교를 위해선, key 값은 변하지 않는 고유한 값이어야만 합니다.
배열의 인덱스로 key를 사용하는 경우가 있는데, 이는 지양해야 합니다.
항목들이 재배열되는 경우엔, 항목의 순서가 계속 변경되어 key 또한 변경되며 코드가 비효율적으로 동작합니다.
실제로 dnd(드래그앤드랍) 기능을 지원하는 칸반보드 구현 시, key 값을 인덱스가 아닌 고유한 값을 받아와 부여해 map으로 뿌렸습니다.
[실제 구현 코드]
[작동 영상]
잘봤습니다. 좋은 글 감사합니다.