[Deep-dive] diff Algorithm

0l0jjo·2023년 7월 17일
0

DEEP-DIVE

목록 보기
1/1
post-thumbnail

가상 돔(Virtual DOM)은 이전 버전의 가상 돔과 새로운 버전의 가상 돔을 비교하는 과정에서 ‘비교 알고리즘’을 따라 동작합니다. 이번 포스팅에서는 비교 알고리즘의 간단한 동작 원리를 살펴보도록 하겠습니다.

비교 알고리즘 동작 원리

  1. 두 엘리먼트의 루트 엘리먼트부터 비교합니다.
  2. 엘리먼트의 타입이 다른 경우, 이전 가상 돔 트리를 버리고 완전히 새로운 트리를 구축합니다.
  3. 엘리먼트의 타입이 같은 경우, 속성을 확인하여 동일한 속성은 유지하고 변경된 속성들만 갱신합니다.
  4. 이후 자식 리스트를 순회하면서 비교하고, 차이점이 있다면 변경된 엘리먼트를 생성합니다.
  5. 각 자식 요소를 고유하게 인식하기 위해 자식 엘리먼트에는 고유한 key prop을 주는 것이 좋습니다.
  6. 그렇지 않은 경우, 모든 엘리먼트가 변경된 것으로 인식하여 요소를 다시 만들어 렌더링해 성능에 악영향을 줍니다.

예시 코드

아래는 가상 돔 비교 알고리즘의 동작을 코드 예시를 통해 확인하는 코드입니다.

<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으로 뿌렸습니다.

[실제 구현 코드]

[작동 영상]

profile
노력 없는 결과는 없다.

4개의 댓글

comment-user-thumbnail
2023년 7월 17일

잘봤습니다. 좋은 글 감사합니다.

1개의 답글
comment-user-thumbnail
2023년 7월 17일

저도 개발자인데 같이 교류 많이 해봐요 ㅎㅎ! 서로 화이팅합시다!

1개의 답글