Section 4 Unit4 - [React] 심화

BRANDY·2023년 3월 23일
0

Virtual DOM

가상의 DOM 객체이며 Real DOM의 가벼운 사본과 같다.

Real DOM

Document Object Model, 문서 객체 모델이다.
문서 객체란 브라우저가 JavaScript와 같은 스크립팅 언어가 html, head, body 같은 태그들에 접근하고 조작할 수 있도록 문서를 트리구조로 객체화한 것이다.

querySelector, addEventListener와 같은 DOM API를 통해 문서의 요소들을 조작할 수 있다.

즉 DOM은 브라우저가 HTML 문서를 조작할 수 있도록 트릴 구조화한 객체 모델이며 데이터 저장의 의미보다는 저장된 데이터를 더 효과적으로 탐색하기 위해 사용되며 빠른 자료 탐색 성능이 장점인 자료구조이다.

그러나 DOM이 변경되고 업데이트가 된다는 것은 DOM 트리를 재구축하는것이며 결국 브라우저의 렌더링 엔진 또한 리플로우(Reflow)한다는 것인데 이는 레이아웃 재연산과 화면에 그려내는 Repaint 과정을 거치게 되고 변화가 필요없는 부분도 변경되며 잦은 리플로우로 인해 성능을 떨어뜨리고 DOM 업데이트 비용이 발생한다.

변화가 필요하지 않은 요소도 변경되어 프레임 드랍(Frame Drop)과 같은 치명적인 UX문제가 발생할 수 있다.

프레임 드랍은 웹 애플리케이션에서 프레임 레이트(Frame Rate)가 떨어져 화면이 버벅대거나 부드럽게 표시되지 않는 것을 의미합니다. 이는 사용자 경험을 저하시키고, 애플리케이션의 성능을 떨어뜨릴 수 있으며, 특히 DOM 조작이 빈번하게 일어날 때 더욱 발생할 가능성이 높습니다.

Virtual DOM 이란?


가상 DOM은 실제 DOM과 동기화되어 상태가 변경될 때마다 가상 DOM을 새로 생성하여 이전 상태와 비교하고 변경이 필요한 부분만 실제 DOM에 반영하여 업데이트하므로 전체 UI를 다시 그리지 않아도 된다.

React에는 DOM객체에 대응하는 가상의 DOM 객체가 있는데 상대적으로 무거운 DOM에 비해 가상 DOM객체는 자바스크립트 객체로 이루어져 있기 때문에 실제 DOM 객체와 동일한 속성을 가지고 있음에도 훨씬 가벼운 사본이다. 실제 DOM 객체처럼 화면에 표시되는 내용을 직접 변경하지는 않는다.

Virtual DOM의 형태

실제 DOM과 마찬가지로 가상 DOM도 HTML 문서 객체를 기반으로 하며 추상화만 되었을 뿐 평범한 자바스크립트 객체이므로 실제 DOM을 건드리지 않고도 필요한 만큼 자유롭게 조작할 수 있다.

가상 DOM은 리액트에서 컴포넌트의 상태나 속성이 변경될 때마다 새로 생성되며 리액트는 이전 가상 DOM과 새로운 가상 DOM을 비교하여 변경된 부분만 실제 DOM에 반영한다. 일일이 수행하지 않고 일괄적으로 한번에 업데이트 하며 이를 재조정(Reconciliation)이라고 한다.

Diffing 알고리즘을 사용하여 변경된 부분을 감지하며 이 알고리즘이 변화를 감지할 수 있도록 직접 할당이 아닌 setState와 같은 메서드를 활용해 상태를 변경해야한다.

Virtual DOM이 실제 DOM을 직접 조작하는것보다 빠르다는것은 맞지만 때로는 직접 DOM을 조작하는것이 더 빠를 수 있다. 실제 DOM 조작이 느려지는 대부분의 경우는 DOM 조작이 발생할 때마다 브라우저에서 다시 레이아웃을 계산하고 페이지를 다시 그리기 때문이기에 가상 DOM을 활용하여 실제 DOM 조작을 최소화 하는것이 성능 최적화의 핵심이다.

React가 DOM 트리를 탐색하는 방법

React는 가상 DOM 트리와 새롭게 변경된 가상 DOM 트리를 비교할 때, 트리의 레벨 순서대로 순회하는 너비 우선 탐색(BFS)의 일종인 방식으로 탐색한다.

다른 타입의 DOM 엘리멘트인 경우

DOM 트리는 각 HTML 태그마다 각각의 규칙이 있어 그 아래 들어가는 자식 태그가 한정적이다. 예를 들어 ul 태그 밑에는 li 태그만 와야 한다던가, (p태그 안에 p태그를 또 쓰지 못하는 등) 자식 태그의 부모 태그 또한 정해져있다는 특징이 있어 부모 태그가 달라진다면 React는 이전 트리를 버리고 새로운 트리를 구축해버린다.

<div>
	<Counter />
</div>

//부모 태그가 div에서 span으로 바뀝니다.
<span>
	<Counter />
</span>

이렇게 부모 태그가 바뀌어버리면 React는 기존의 트리를 버리고 새로운 트리를 구축하기 때문에 이전의 DOM 노드들은 전부 파괴된다. 즉 div가 span으로 바뀌면 자식 노드인 Counter는 완전히 해제되는 것이다. span 태그 속 새로운 Counter가 다시 실행된다.

같은 타입의 DOM 엘리먼트인 경우

타입이 바뀌지 않는다면 React는 최대한 렌더링 하지 않는 방향으로 최소한의 변경사항만 업데이트 하며 업데이트 할 내용이 생기면 virtual DOM 내부의 프로퍼티만 수정한 뒤, 모든 노드에 걸친 업데이트가 끝나면 그때 단 한번 실제 DOM으로의 렌더링을 시도한다.

<div className="before" title="stuff" />

//기존의 엘리먼트가 태그는 바뀌지 않은 채 className만 바뀌었습니다.
<div className="after" title="stuff" />

예를 들어

//className이 before인 컴포넌트
<div style={{color: 'red', fontWeight: 'bold"}} title="stuff" />

//className이 after인 컴포넌트
<div style={{color: 'green', fontWeight: 'bold"}} title="stuff" />

React는 정확히 fontWeight 및 다은 요소는 수정하지 않고 color스타일만 바뀌고 있다. 이어 해당 노드들 밑의 자식들을 순차적으로 동시에 순회하면서 차이가 발견될 때마다 변경하는데 이를 재귀적으로 처리한다고 표현한다.

profile
프런트엔드 개발자

0개의 댓글