DOM 이란?
문서 객체 모델은 HTML, XML 문서의 프로그래밍 interface 입니다. DOM은 문서(HTML)의 구조화된 표현을 제공하며 프로그래밍 언어가 DOM 구조에 접근할 수 있는 방법을 제공하여 그들이 문서 구조, 스타일, 내용 등을 변경할 수 있게 돕는 역할을 합니다.
'객체 지향'적 설계
그러므로, document를 포함한 html, 그 아래의 트리구조의 태그들 모두 객체이며 모두 객체로서 접근 및 컨트롤 할 수 있습니다.
HTML (HyperText Markup Language) : 웹 페이지를 구성하기 위한 마크업 언어
XML (eXtensible Markup Language) : 여러 방면으로 사용가능한 마크업 언어
DOM API 예시로는
document.getElementById(id)
document.createElement(name)
element.style.left
class와 id를 이용한 객체 컨트롤
등이 있다.
DOM의 브라우저 렌더링 과정
브라우저가 html을 전달받게 되면 이것을 바탕으로 DOM트리를 구성한다.
DOM 트리는 css와 함께 화면을 그려줄 render 트리를 구성한다.
layout과 paint를 통해 화면에 보여진다.
DOM의 단점 및 문제점
브라우저에서 DOM의 변화가 일어나게되면, 브라우저는 위의 렌더링 과정을 다시 거치는 비효율적인 면이 발생함. (한 페이지에서 많은 조작이 일어나는 SPA에서는 더더욱 비효율적임.)
DOM의 엘리먼트를 조작하는 과정에서 쓰였던 기존의 document.getElementById()나 제이쿼리 같은 API가 프로그램의 규모가 커지면 엘리먼트의 수도 늘어나고 이벤트도 늘어나기 떄문에 api 조작이 불편해짐
Virtual DOM
Reconciliation(재조정)
전체 DOM 트리를 탐색하고 비교하는 일반적인 알고리즘 (diff algorithm)이 있지만, 이 알고리즘은 O(N^3)의 복잡도를 갖습니다.
예를들어, 1000개의 엘리먼트를 그리기 위해 10억 번의 비교연산을 수행해야 합니다. React는 대신, 두 가지 가정을 기반하여 O(n) 복잡도의 휴리스틱 알고리즘을 구현했습니다.
React는 DOM 트리를 level-by-level로 탐색합니다. 너비 우선 탐색의 일종이라 볼 수 있습니다.
같은 타입의 두 React DOM 엘리먼트를 비교할 때, React는 두 엘리먼트의 속성을 확인하여, 동일한 내역은 유지하고 변경된 속성들만 갱신합니다.
자식 엘리먼트의 순서가 다른 경우는 매우 비효율적으로 작업을 수행하게 된다.
<ul>
<li>first</li>
<li>second</li>
</ul>
⬇︎
<ul>
<li>zero</li> {/* first가 zero가 됐군. 새로 렌더링! */}
<li>first</li> {/* second가 first가 됐군. 새로 렌더링! */}
<li>second</li> {/* 추가됐네. 새로 렌더링! */}
</ul>
이와 같은 비효율적인 문제는 key를 통해 해결 될 수 있다.
<ul>
<li key="a">first</li>
<li key="b">second</li>
</ul>
⬇︎
<ul>
<li key="c">zero</li> {/* 추가됐네. 새로 렌더링! */}
<li key="a">first</li> {/* 아까 그 녀석이군. 순서만 바꾸자. */}
<li key="b">second</li> {/* 아까 그 녀석이군. 순서만 바꾸자. */}
</ul>html
Reconciliation Process의 과정
결론
이렇듯 React는 Virtual DOM을 통해 렌더를 한 번으로 줄여 효율적으로 HTML을 제어하고 됩니다.
추가로 리액트를 사용하는것이 무조건적인 성능 향상이 아닙니다. 성능적인 측면도 중요하지만 프론트엔트 뷰 라이브러리를 사용했을 때의 장점은 데이터의 흐름과 구성을 일관되게 해준다는것이 장점입니다. 리액트를 사용하기 전에는 데이터의 소스와 DOM의 조작에 대한 자유도가 높기 때문에 일관된 패턴의 코드를 짜기 어려웠지만 리액트를 사용합으로써 데이터의 흐름을 강제하고, 데이터의 변화에 따라 화면에 변화를 쉽게 확인할 수 있게 되었습니다.