React를 공부하신 분들이라면 가상(Virtual) DOM이라는 말을 한번쯤은 들으셨을 법도 한데, 이게 왜 중요한지는 가물가물하실 겁니다.
그래서 글로 정리해보았어요들레이요.

웹사이트를 화면에 표시할 때 HTML, CSS, JavaScript가 사용된다는 건 아실 거에요.
실제로는 HTML, CSS, JavaScript 코드가 화면에 보이는 웹사이트로 변신(?)될때까지는 일련의 과정이 이루어지는데, 이를 Critical Rendering Path라 합니다.

대충 과정을 정리해 보자면
HTML 코드 DOM 트리
-------------------------------- ----------------------------
<html> [html]
<body> ├── [body]
<h1>무적 LG</h1> │ ├── [h1] "무적 LG"
<p>끝까지 TWINS</p> │ └── [p] "끝까지 TWINS"
</body> └──
</html>
-------------------------------- ----------------------------
CSS 코드 CSSOM 트리
-------------------------------- ----------------------------
h1 { color: pink; } [CSSOM]
p { font-size: 24px; } ├── [h1]
│ └── color: pink
└── [p]
└── font-size: 24px
-------------------------------- ----------------------------
1단계 HTML 코드는 DOM(Document Object Model), CSS 코드는 CSSOM (CSS Object Model)로 전환됩니다.
2단계 DOM + CSS Object Model을 합쳐서 렌더 트리를 만듭니다.
3단계 렌더 트리 내 요소의 위치를 계산하는 Layout 단계가 진행됩니다.
4단계 레이아웃이 계산된 요소들을 실제로 웹사이트에 그리는 Paint 단계가 진행됩니다.
앞서 언급했듯이 JavaScript로는 DOM을 수정할 수 있습니다.
이런 경우 브라우저는 다시 render tree를 생성하고(2단계), 웹사이트의 레이아웃을 다시 잡는 reflow를 거치고(3단계), 렌더링 역시 다시 하여 repaint(4단계)도 거치게 됩니다.
문제는 reflow와 repaint에는 큰 시간적 비용이 든다는 점입니다. 그래서 DOM 수정이 많아질수록 웹사이트 성능이 급격히 떨어집니다.
이를테면, <ul>에 0부터 2999까지 <li>를 삽입하는 함수를 만들었다고 합시다
function badPractice() {
const $ul = document.getElementById("ul");
for (let i = 0; i < 3000; i++) {
$ul.innerHTML += `<li>${i}</li>`;
}
}
위 함수에서는 무려 3000번 DOM 수정을 하게 됩니다. reflow와 repaint 역시 오래 걸리기 때문에, 실제로 <li> 태그 내용이 다 생성되려면 상당한 시간이 소요됩니다. 즉 렌더링이 많이 느려지므로, 이렇게 코드를 짜시면 안 됩니다.
function goodPractice(){
let list = "";
for (let i = 0; i < 3000; i++){
list += `<li>${i}</li>`
}
const $ul = document.getElementById("ul");
$ul.innerHTML = list;
}
대신 이렇게 list라는 String 매개변수를 선언한 뒤, <li> 태그에 해당하는 내용을 미리 저장해 두고, DOM은 단 1번 수정하는 식으로 코드를 짜시면 됩니다.
이렇게 한꺼번에 변경사항이 많을 경우, 매번 따로 DOM 수정을 하기보단, 한 번에 모아서 수정을 해야 합니다.
React에서는 컴포넌트와 state를 통해 업데이트를 관리한다는 점을 기억합시다. 컴포넌트 내 State가 바뀔 때마다 컴포넌트 UI가 업데이트되는 방식이였죠.
앞선 논리대로라면 여러 업데이트가 발생할 시, 모아서 한 방에 DOM에 반영해야 하는 게 좋을 겁니다. 이를 위해 리액트는 Virtual DOM을 사용하는데요, 이는 실제 브라우저가 렌더링하는 DOM을 자바스크립트 객체로 흉내낸 거라고 생각하면 됩니다.

자세한 동작과정을 보자면
이러면 Reflow, Repaint가 최소화되어 훨씬 빠른 렌더링이 가능해집니다. 우와~
우와 짱이당~