
https://ko.reactjs.org/docs/reconciliation.html
React 만의 diff 알고리즘을 활용한 비교 후 rendering까지의 과정
리액트를 활용하여 개발을 할 때 "리액트는 SPA이고 변경 되는 컴포넌트만 변경이 된다" 정도만 알고있었고 어느 시점에서, 또는 어떤 정확한 기준에서 변경이 되는지 정확히 알지는 못했었다.
React는 Real DOM 과 virtual DOM을 가지고 root에서부터 비교를 시작한다. 비교 알고리즘을 돌면서 각 태그를 검사한다.
<div>
<Counter />
</div>
// change to ->
<span>
<Counter />
</span>
DOM 엘리먼트의 타입이 같은 경우 (갱신)
React는 현재 DOM 노드 상에 className만 수정합니다. (className 은 attribute node 에 속해있습니다.)
<div style={{color: 'red', fontWeight: 'bold'}} />
<div style={{color: 'green', fontWeight: 'bold'}}
DOM 노드의 자식들을 재귀적으로 처리할 때, React는 기본적으로 동시에 두 리스트를 순회하고 차이점이 있으면 변경을 생성합니다.
<ul>
<li>first</li>
<li>second</li>
</ul>
<ul>
<li>first</li>
<li>second</li>
**<li>third</li>**
</ul>
React는 기존 트리에 하위로 추가 된 경우 first, second는 변경이 없고 third 만 추가 되었다 인식하여 third만 트리에 추가합니다.
<ul>
<li>Duke</li>
<li>Villanova</li>
</ul>
<ul>
<li>Connecticut</li>
<li>Duke</li>
<li>Villanova</li>
</ul>
위와 같이 마지막에 덧 붙히는 것 이 아닌 다른 위치에 변경이 발생되면 변경된 요소로 부터 트리를 파괴하고 다시 그리게 된다. 비효율적이다.
위와 같은 경우를 위해서 tag에 key 값을 추가 할 수 있다. 자식들이 key 를 가지고 있다면 위치와 상관없이 key를 우선 비교하여 realDOM 자식과 virtualDOM의 자식이 일치하는지 확인한다.
key는 전역으로 관리할 필요가 없이 형제 관계에서만 식별할 수 있으면 된다.
<ul>
<li key="11">Duke</li>
<li key="12">Villanova</li>
</ul>
<ul>
<li key="11">Connecticut</li>
<li key="12">Duke</li>
<li key="13">Villanova</li>
</ul>
자주쓰는 코드 중 Array.map()에서 key를 index로 전달해주는 경우가 간혹 있는데, 해당 부분은 이미 eslint 에서도 막지만 마지막에 추가 되는 것이 아닌 다른 위치에 새로운 데이터가 추가되는 경우 key로 인해 버그가 생길 수도 있다.
SampleArray.map((item, index) => <div key={index}>{item.name}</div>)
render의 결과물이 비슷한 컴포넌트들의 경우 타입을 유사하게 만들어 하나로 만드는것이 불필요한 DOM 노드의 재생성을 막을 수 있다.
key는 항상 변경되지 않고, 고유하며, 속해있는 자식 관계에서 유일해야합니다. Math.random()같이 변경되는 값을 사용하면 불필요한 DOM을 재생성하여 성능이 나빠질 수 있습니다.