가상DOM — React가 화면을 빠르게 바꾸는 비밀
Article
1편에서 브라우저가 화면을 그리는 과정을 배웠습니다. HTML을 DOM 트리로 만들고, CSS와 합쳐서 레이아웃을 계산하고, 페인트하는 과정이었습니다.
그런데 문제가 있습니다. DOM을 직접 바꿀 때마다 이 과정이 반복됩니다. React는 이 문제를 해결하기 위해 **가상DOM(Virtual DOM)**이라는 전략을 사용합니다.
실제 DOM을 직접 바꾸면 왜 느릴까요
퍼블리싱할 때 JavaScript로 DOM을 직접 조작한 경험이 있을 겁니다.
document.querySelector('.title').textContent = '새 제목';
document.querySelector('.count').textContent = '10';
document.querySelector('.status').style.color = 'red';
이 코드에서 DOM을 세 번 바꾸고 있습니다. 문제는 매번 브라우저가 레이아웃을 다시 계산하고 화면을 다시 그릴 수 있다는 점입니다.
변경이 몇 개 없으면 괜찮지만, 복잡한 웹 앱에서 한 번의 클릭으로 수십 개의 요소가 바뀌어야 한다면? 매번 리플로우와 리페인트가 일어나면 화면이 버벅거립니다.
가상DOM이란
가상DOM은 메모리 안에 만들어둔 가짜 DOM입니다. 진짜 DOM의 복사본이라고 생각하면 됩니다.
React는 화면을 업데이트할 때 이런 과정을 거칩니다.
- 상태가 바뀌면, 새로운 가상DOM을 만듭니다.
- 이전 가상DOM과 새 가상DOM을 비교합니다.
- 달라진 부분만 찾아냅니다.
- 그 부분만 실제 DOM에 반영합니다.
핵심은 3번입니다. 전체를 다시 그리는 게 아니라, 바뀐 부분만 골라서 최소한으로 업데이트합니다.
비유: 문서 수정
보고서를 수정하는 상황을 떠올려보세요.
가상DOM 없이 (직접 수정)
- 10페이지짜리 보고서에서 한 문장을 고치는데, 전체 보고서를 처음부터 다시 출력합니다.
가상DOM 사용 (비교 후 수정)
- 수정 전 보고서와 수정 후 보고서를 나란히 놓고 비교합니다.
- "3페이지 두 번째 문단만 달라졌네" 하고 확인합니다.
- 그 부분만 교체합니다.
어떤 방식이 효율적인지는 분명합니다. React의 가상DOM이 바로 두 번째 방식입니다.
Diffing 알고리즘
이전 가상DOM과 새 가상DOM을 비교하는 과정을 **Diffing(디핑)**이라고 부릅니다. React는 이 비교를 매우 빠르게 수행합니다.
비교 규칙은 간단합니다.
- 태그가 바뀌면: 그 요소와 자식 전체를 새로 만듭니다. (예:
<div>가<span>으로 바뀐 경우) - 태그는 같고 속성만 바뀌면: 속성만 업데이트합니다.
- 자식 요소 비교: 위에서 아래로 순서대로 비교합니다.
이렇게 비교한 결과, 달라진 부분만 모아서 한 번에 실제 DOM에 반영합니다. 이 과정을 **재조정(Reconciliation)**이라고 합니다.
전체 흐름 정리
상태 변경
↓
새로운 가상DOM 생성
↓
이전 가상DOM과 비교 (Diffing)
↓
달라진 부분만 파악
↓
실제 DOM에 최소한의 변경만 반영
↓
브라우저가 화면을 다시 그림
가상DOM이 항상 빠른 건 아닙니다
오해하기 쉬운 부분이 있습니다. 가상DOM이 "진짜 DOM보다 빠르다"는 건 정확한 표현이 아닙니다.
가상DOM도 결국 비교 작업을 하고, 마지막에는 실제 DOM을 건드립니다. 비교하는 비용이 추가되는 겁니다.
하지만 복잡한 UI에서 무작정 DOM을 여러 번 바꾸는 것보다는 변경 사항을 모아서 한 번에 반영하는 게 대부분의 경우 더 효율적입니다. 가상DOM의 가치는 "빠르다"보다는 "충분히 빠르면서도 개발이 편하다"에 있습니다.
정리
- 가상DOM은 메모리에 만들어둔 DOM의 복사본입니다.
- React는 상태가 바뀌면 새 가상DOM을 만들고, 이전 것과 **비교(Diffing)**합니다.
- 달라진 부분만 실제 DOM에 반영해서 불필요한 리플로우/리페인트를 줄입니다.
- 가상DOM은 "가장 빠른 방법"이라기보다, 효율적이면서 개발하기 편한 방법입니다.
다음 글에서는 이 가상DOM과 밀접하게 연결된 개념, 리렌더링에 대해 알아보겠습니다.