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을 재생성하여 성능이 나빠질 수 있습니다.