이전 글에서 살펴봤듯이
React에서 렌더링은 컴포넌트 함수가 다시 실행되는 과정이고,
이 자체는 생각보다 큰 비용이 들지 않는 작업이다.
그렇다면 여기서 자연스럽게 하나의 질문이 생긴다.
그럼 실제로 성능에 영향을 주는 건 무엇일까?
핵심은 렌더링 자체가 아니라,
렌더링 이후 실제 화면을 업데이트하는 과정,
즉 DOM을 다루는 작업이다.
JavaScript에서 변수 하나 바꾸는 건 가볍다.
하지만 DOM은 다르다.
DOM을 변경하는 순간 브라우저는 단순히 값만 바꾸는 게 아니라
화면을 다시 계산하는 과정을 거친다.
예를 들어 생각해보면 이런 느낌이다.
즉 DOM을 건드린다는 것은 단순히 값을 바꾸는 것이 아니라,
브라우저에게 화면을 다시 계산하고 그리도록 요청하는 것과 같다.
만약 DOM을 계속 직접 조작하게 되면 어떻게 될까?
element.textContent = "A";
element.textContent = "B";
element.textContent = "C";
이렇게 여러 번 바꾸면
브라우저는 그때마다 화면을 다시 계산하려고 한다.
결과적으로 불필요한 작업이 계속 발생한다.
그럼 단순하게 DOM을 덜 건드리면 되는 게 아닌가 싶은 생각이 들 수 있다.
그래서 이 지점에서 React의 방식이 등장한다.
앞에서 본 것처럼
문제는 렌더링이 아니라 DOM을 직접 자주 변경하는 것이었다.
그렇다면 해결 방법은 단순하다.
DOM을 바로 건드리지 말고, 한 번 모아서 처리하자
이 아이디어에서 등장한 것이 바로 Virtual DOM이다.
Virtual DOM은 말 그대로
실제 DOM이 아니라, 메모리 위에 만들어진 DOM의 표현(추상화된 구조)다.
React는 상태가 변경되면
새로운 Virtual DOM을 생성하고 이전 Virtual DOM과 비교하여 변경 사항을 계산한다.
구조를 보면 다음과 같다.
핵심은 하나다.
비싼 작업은 최소화하고, 싼 작업은 여러 번 해도 된다
그래서 React는 Virtual DOM을 통해 변경 사항을 여러 번 계산하고
실제 DOM 변경은 필요한 부분에만 최소한으로 적용하는 방식을 선택한 것이다.
이번에도 공사로 비유할 수 있다.
직접 DOM을 건드리는 방식은 수정할 때마다 바로 공사하는 느낌이다.
벽 하나 바뀌면 공사, 창문 하나 바뀌면 또 공사하는 방식이라면,
Virtual DOM은 설계도를 먼저 수정한 뒤, 필요한 부분만 실제 공사에 반영하는 방식이다.
설계도에서 바뀐 부분을 정리하고 실제 공사는 필요한 부분만 진행하는 방식이다.
즉 Virtual DOM은 화면을 그리기 위한 것이 아니라,
변경 사항을 계산하기 위한 중간 단계라고 볼 수 있다.
Virtual DOM을 쓴다는 건 알았다.
그럼 중요한 건 이거다.
어떻게 비교하고, 어떻게 최소 변경만 반영할까?
React는 상태(state)나 props가 변경되어 렌더링이 발생할 때
새로운 Virtual DOM을 만든다.
그리고 그 이전 Virtual DOM과 새로운 Virtual DOM을
비교해서 달라진 부분을 찾는다.
이 과정을 보통 diffing이라고 한다.
비교 과정에서 React는 단순히 전체를 바꾸지 않고,
어디가 바뀌었는지를 찾는다.
예를 들어
<h1>Hello</h1>
에서
<h1>Hello World</h1>
로 바뀌었다면
<h1> 요소 자체를 교체하는 것이 아니라
내용만 변경한다고 판단한다.
diffing으로 변경된 부분을 찾았으면
이제 그걸 실제 DOM에 반영한다.
이 과정을 Reconciliation이라고 한다.
핵심은 필요한 부분만 업데이트한다는 것이다.
요소 타입이 같으면 내부 내용과 속성을 업데이트하고,
요소 타입이 다르면 기존 요소를 제거하고 새로 생성한다.
이 방식 때문에 React는
전체를 다시 그리지 않고 필요한 부분만 변경한다.
즉 다음과 같은 구조가 된다.
이게 가능한 이유는
렌더링 과정은 대부분 JavaScript 계산 작업으로 비교적 가볍고,
실제 DOM 변경은 브라우저의 레이아웃과 화면 업데이트 과정이 포함되어
비용이 크기 때문이다.
그래서 React는 렌더링을 다시 수행하여 Virtual DOM을 만들고
변경 사항을 비교하는 과정은 여러 번 수행하되,
실제 DOM 변경은 필요한 부분에만 최소한으로 적용하는 전략을 선택했다.
결국 React는 화면을 바로 변경하는 방식이 아니라,
먼저 Virtual DOM을 통해 변경 사항을 계산하고,
이전 결과와 비교하여 바뀐 부분만 실제 DOM에 반영하는 방식으로
화면을 업데이트한다.
즉 React의 렌더링 구조는
렌더링 → 비교 → 실제 DOM 반영
이라는 단계로 이루어져 있다고 볼 수 있다.