DOM (Document Object Modal) 은 HTML / XML 문서에 접근하기 위한 인터페이스이다. 브라우저는 HTML 문서를 파싱하여 사용자에게 시각화한다.
이때 우리는 여러 가지 이유로 브라우저가 띄워주는 HTML 문서에 어떤 동적 처리를 해 주고 싶을 텐데, 그 과정을 도와주는 인터페이스가 DOM이다.
기존의 DOM은 브라우저 렌더 과정 에 따라 DOM의 조작은 브라우저 렌더 과정을 유발한다. 만약 3천번의 변화가 생기면, 렌더링도 3천번 일어나게 된다. 이런 경우 상당히 비효율적인데, Virtual DOM은 이를 위해 만들어졌다. 즉, DOM을 반복적으로 직접 조작하면 그 만큼 브라우저가 렌더링을 자주하게 되고, 그 만큼 PC 자원을 많이 소모하게되는 문제를 해결하기 위해 만들어진 것이 Virtaul DOM이다.
React 공식문서에서는 Virtual DOM을 UI의 이상적인 또는 “가상”적인 표현을 메모리에 저장하고 ReactDOM과 같은 라이브러리에 의해 “실제” DOM과 동기화하는 프로그래밍 개념
이라고 정의하고 있다. DOM을 추상화한 가상의 객체라고 생각하면 될 것 같다.
Virtual DOM에 적용하는 변경사항은 DOM에 바로 반영되지 않고, 변경사항들을 모아뒀다가, 한번에 DOM한테 보낸다. DOM은 업데이트를 딱 한 번만 하면 되고, 그러면 렌더도 한 번만 하면 된다. 따라서 DOM 조작이 아주 빈번할 경우 Virtual DOM은 DOM을 조작하는 것에 비해 효율적으로 동작할 것이다.
그런데 문제는, 그냥 DOM을 조작하는 것보다 Virtual DOM을 조작하고 DOM을 조작하는 것이 더 느리다. 왜냐하면, Virtual DOM의 작동 원리는 하나의 레이어를 더 거쳐가는 동작이기 때문에, DOM 조작이 아주 많지 않다면 "당연하게도" DOM을 직접 조작하는 것보다 느리다.
리액트는 항상 두개의 가상 돔 객체를 가지고 있다.
1. 렌더링 이전 화면 구조를 나타내는 가상돔
2. 렌더링 이후에 보이게 될 화면 구조를 나타내는 가상돔
리액트는 상태가 변경될 때마다 리렌더링이 일어나게 된다. 그리고 실제 브라우저가 그려지기 전에, 상태가 변경될 때마다 새로운 가상 돔 객체를 생성하게 된다.
렌더링 이전에 화면의 내용을 담고있는 첫번째 가상돔과 업데이트 이후에 발생할 두번째 가상돔을 비교해 정확히 어떤 Element가 변했는지를 비교하는걸 React에선 Diffing이라고 한다.
Diffing은 효율적인 알고리즘을 사용해 진행되기 때문에 어떤 Element에 차이가 있는지를 매우 신속하게 파악할 수 있게 되고, React는 이를 통해 변경된 부분만을 브라우저상의 실제 DOM에 적용하게 된다. 이 과정을 Reconciliation(재조정)이라고 한다.
이 과정이 매우 효율적인 이유는 Batch Update때문인데, 이는 변경된 모든 사항을 집단화시켜 한번에 실제 DOM에 적용하는 방식이다. DOM조작에 비용이 가장 많이 발생하는 지점은 브라우저에 화면을 그려주는 작업인 만큼 Batch Update는 변경된 Element를 별개로 그려주는 것이 아닌, 변경된 내용을 한 번에 받아와 이를 실제 DOM에 한번에 적용시켜준다는 점이 효율적이라는 것이다.