Virtual Dom이란? Reconciliation 이란?

React는 Virtual DOM을 이용하여 실제 DOM을 제어하는 것보다 성능을 올렸다고 합니다.

그럼, 왜 Vritual DOM을 제어하는게 DOM을 제어하는 것보다 좋을까요? 또 어떻게 제어할까요?

Virtual DOM?

virtual DOM(VDOM)은 실제 'DOM' 또는 렌더링 환경(iOS, Android 같은)과 동기화 할 수 있는 'virtual'한 UI 표현 방식을 뜻하는 프로그래밍 개념 입니다.

왜 VDOM?

DOM은 HTML같은 document를 표현하기 위해서 트리구조를 이용합니다. 그러나 script에 의해서 DOM이 속성이 변경이 되어야 한다면 전체 app를 리렌더링 해야하는 단점이 있습니다. VDOM은 전체 app를 리렌더링 하는 대신 최소한의 DOM만 조작할 수 있게 해줍니다. 여기서 실제 DOM과 VDOM을 비교하는 것을 reconcilation 이라고 부릅니다

React는 declartive API를 제공해주어 개발자는 react 내부에서 어떤 일이 일어나고 있는지 모르며 알 필요가 없습니다. 이렇게 해주는 것은 reconciliation 때문이며 개발자가 더 쉽게 개발을 할 수 있게 도와 줍니다.

Reconcilation?

React의 render() 함수는 state나 props가 갱신되면 새로운 React Element Tree를 반환 합니다. 이 때 React는 이전 트리를 방금 만들어진 트리에 맞게 가장 효과적으로 UI를 갱신하는 방법을 알아 내야 합니다

하나의 트리를 다른 트리로 변환하기 위한 최소한의 연산 수를 구하는 알고리즘의 일반적인 복잡도는 O(n^3)의 복잡도를 가집니다.

React에서 이 알고리즘을 적용하면, 1000개의 Element가 있다면 10억번의 비교 연산을 해야 합니다. 너무나도 비싼 연산 이죠.. React는 대신 두가지 가정을 기반하여 O(n) 복잡도를 가진 알고리즘을 구현했습니다.

  1. 서로 다른 타입의 두 엘리먼트는 서로 다른 트리를 만들어낸다.
  2. 개발자가 key prop를 통해, 여러 렌더링 사이에서 어떤 자식 엘리먼트가 변경되지 않아야 할지 표시해 줄 수 있다.

엘리먼트의 타입이 다른 경우

두 root 엘리먼트의 타입이 다르면 React는 이전 트리를 버리고 완전히 새로운 트리를 구축합니다.

<div>
  <Counter />
</div>

<span>
  <Counter />
</span>

이전 Couter는 사라지고, 새로운 Counter가 다시 마운트 될 것입니다.

DOM 엘리먼트의 타입이 같은 경우

같은 타입의 두 React DOM 엘리먼트를 비교할 때, React는 두 엘리먼트의 속성을 확인하여, 동일한 내역은 유지하고 변경된 속성들만 갱신합니다.

<div className="before" title="stuff" />

<div className="after" title="stuff" />

위 두 엘리먼트를 비교하면, React는 현재 DOM 노드 상에 className만 수정합니다.

같은 타입의 컴포넌트 엘리먼트

컴포넌트가 갱신되면 인스턴스는 동일하게 유지되어 렌더링 간 state가 유지됩니다.

자식에 대한 재귀적 처리

DOM 노드의 자식들을 재귀적으로 처리할떄, React는 기본적으로 동시에 두 리스트를 순회하고 차이점이 있으면 변경을 생성합니다.

<ul>
  <li>first</li>
  <li>second</li>
</ul>

<ul>
  <li>first</li>
  <li>second</li>
  <li>third</li>
</ul>

React는 두 트리에서 <li>first</li>가 일치하는 것을 확인하고 <li>second</li>가 일치하는 것을 확인합니다. 그리고 마지막으로 <li>third</li>를 트리에 추가합니다.

하지만 위와 다르게 리스트의 맨 앞에 엘리멘트를 추가하는 경우 성능이 좋지 않습니다.

<ul>
  <li>Duke</li>
  <li>Villanova</li>
</ul>

<ul>
  <li>Connecticut</li>
  <li>Duke</li>
  <li>Villanova</li>
</ul>

React는 종속 트리를 그대로 유지하는 대신 모든 자식을 변경합니다. 이러한 비효율은 문제가 될 수 있습니다.

Keys

이러한 문제를 해결하기 위해, React는 key속성을 지원한니다. 자식들이 key를 가지고 있다면, React는 key를 통해 기존 트리와 이후 트리의 자식들이 일치하는지 확인합니다.

<ul>
  <li key="2015">Duke</li>
  <li key="2016">Villanova</li>
</ul>

<ul>
  <li key="2014">Connecticut</li>
  <li key="2015">Duke</li>
  <li key="2016">Villanova</li>
</ul>

React는 '2014'key를 가진 엘리먼트가 새로 추가되었다는 것을 인지하고 '2015''2016'key를 가진 엘리먼트는 그저 이동만 하면 되는 것을 알 수 있습니다.

진짜 DOM은 매번 모든 App를 리렌더링 할까?

아니요 그렇지 않습니다. Web은 shadow DOM을 사용하여 DOM 트리에 속한 엘리먼트에 부착될 수 있게 해줍니다.

관련자료

좋은 웹페이지 즐겨찾기