리액트는 선언적 API를 제공하기 때문에 리액트의 사용자는 렌더링 작업을 함에 있어서 매번 무엇이 바뀌었는지를 걱정할 필요가 없습니다. 하지만 내부에서는 기존의 VDOM과 변경사항이 생긴 VDOM의 비교작업이 이루어집니다. 이 과정을 재조정(Reconcilitaion)이라고 합니다.
이 과정을 거치려면, 실제로 모든 DOM 트리를 순회하면서 탐색 및 변경하는 과정을 거쳐야 합니다. 하지만 이런 모든 과정을 거친다면 최첨단의 알고리즘을 이용해도 O(n^3)의 시간복잡도를 가진다고 합니다.
React는 대신, 두 가지 가정을 기반하여 O(n) 복잡도의 휴리스틱 알고리즘을 구현했습니다.
두 개의 트리를 비교할 때, React는 두 엘리먼트의 루트(root) 엘리먼트부터 비교합니다. 이후의 동작은 루트 엘리먼트의 타입에 따라 달라집니다.
엘리먼트의 타입이 다른 경우
이전 트리를 완전히 버리고 새로운 트리를 구축합니다. 이전 트리와 연관된 모든 state는 사라집니다.
<div>
<Counter />
</div>
<span>
<Counter />
</span>
엘리먼트의 타입이 같은 경우
변경된 속성들에 대해서만 업데이트됩니다. (Color 속성만 업데이트)
<div style={{color: 'black', fontWeight: 'bold'}}>{count}</div>
<div style={{color: 'red', fontWeight: 'bold'}}>{count}</div>
DOM 노드의 자식들을 재귀적으로 처리할 때, React는 기본적으로 동시에 두 리스트를 순회하고 차이점이 있으면 변경을 생성합니다.
자식의 끝에 엘리먼트를 추가하면 두 트리 사이의 변경은 잘 작동하지만 맨 앞에 추가하게 되면 성능이 좋지 않습니다. 아래의 경우엔 모든 자식을 변경하게 됩니다.
<ul>
<li>Duke</li>
<li>Villanova</li>
</ul>
<ul>
<li>Connecticut</li>
<li>Duke</li>
<li>Villanova</li>
</ul>
이를 해결하기 위해, React는 Key
속성을 지원합니다. 자식들이 key를 가지고 있다면, React는 key를 통해 기존 트리와 이후 트리의 자식들이 일치하는지 확인하여 트리의 변환 작업이 효율적으로 수행되도록 합니다.
key props 선정할 때 유의점
- 두 컴포넌트가 교체하는 상황에서는 그 둘을 같은 타입으로 만드는 것이 더 효율적이다.
- key 값을 선정할 때는, 형제 사이에서만 유일하면 되고, 전역에서 유일한 value 일 필요는 없다.
- 배열의 인덱스는 key로 사용하지 않는 것이 좋다. 항목들이 재배열되면, key 값이 변경될 수 있기 때문
- key는 변하지 않고, 예상 가능하면서, 유일해야 한다. (Math.random() 같은 걸 key로 쓰면 안됨)