Front-end/React

[React]리액트 Virtaul DOM이란?

영벨롭 2022. 5. 28. 14:42

[ Real DOM ]

 

 Virtual DOM을 살펴보기 앞서, 원래 브라우저는 어떻게 우리에게 DOM 구조로 보여줬을까요?

 

 

★ 실제 브라우저의 렌더링 과정

 

1. 먼저 브라우저는 서버에게 외부 리소스(html, css, js, img, ...)를 요청하여 그 응답값을 받습니다. 

 

2. 브라우저의 렌더링 엔진은 html과 css를 파싱하여 DOM 트리와 CSSOM 트리를 생성합니다. 

 

3. 브라우저의 렌더링 엔진은 DOM과 CSSOM을 결합하여 Render tree를 생성합니다. 

 

4. 브라우저의 자바스크립트 엔진은 js를 파싱하여 실행합니다. 이때 자바스크립트가 DOM API를 통해 DOM과 CSSOM을 변경할 수 있는데 변경된 트리를 기반으로 Render tree를 재생성합니다. 

 

5. Render tree를 기반으로 노드들의 위치와 크기를 결정(계산) 후(Layout), 브라우저를 통해 시각적으로 보여주게 됩니다.(Paint)

 

 

 

 

 

[ Real DOM의 문제점 ]

 

 그런데 실제 DOM을 조작하는 작업은 비용이 많이 듭니다. 브라우저가 화면을 그리는데 필요한 모든 정보가 들어있기 때문인데요!

 

 문제는 Render tree가 바뀔 때마다 모든 트리를 전부 다시 생성하기 때문에 굉장히 비효율적이라고 할 수 있습니다. 

 

 앞서 말했듯이 DOM에 변화가 생기면, Render tree를 매번 재생성합니다.

 

 Render tree를 재생성 할 때마다 모든 요소들의 스타일과 레이아웃을 다시 계산하며 페인팅 하는 과정을 반복하게 되는 것이죠!

 

 즉, 웹페이지에서 변화가 일어날때마다 그 변화를 적용하기 위해 브라우저가 많은 연산을 해야한다는 것이고 이는 곧 전체적인 프로세스를 비효율적으로 만듭니다. 

 

 만약 30개의 노드 중에서 하나의 노드를 수정하면, 30번의 레이아웃 재계산과 30번의 리렌더링을 초래한다는 것입니다. 

 

 이러한 DOM 조작의 문제를 보완하기 위해 나온 개념이 바로 Virtual DOM입니다. 

 

 

 

 

 

 

[ Virtual DOM ]

 

 기본적으로 Virtual DOM은 실제 DOM과 동일한 상태를 가지고 있고 표현하는 형식만 다를 뿐입니다. 

 

 Virtual DOM은 구조화 되어 메모리에 저장되어 있어, 곧 바로 렌더링 되지 않고 메모리에서 동작하게 됩니다. 

 

 Virtual DOM이 바뀐다면, 우선 렌더링 하지 않고, 메모리에서 연산 동작을 하게 됩니다. 연산이 끝나고나면 최종적인 변화를 하나로 묶어서 딱 한 번 만 실제 DOM에게 보내주는 것입니다.

 

 이렇게 되면 레이아웃 재계산과 리렌더링의 규모는 커지겠지만, 딱 한 번만 리렌더링 되는 것이기 때문의 연산의 횟수를 줄일 수 있고 전체 프로세스를 효율적으로 만들 수 있겠죠!

 

 

★ Virtual DOM 동작 과정

 

 1. 리액트에서는 props의 변화나 setState 호출 등으로 컴포넌트의 상태가 변화하면, 해당 컴포넌트의 shouldComponentUpdate 함수를 실행됩니다. 만약 이 함수가 true라면 render 함수를 실행하고 false라면 실행하지 않습니다. 

 

 2. 이때 변화가 일어난 컴포넌트를 루트 노드 삼아 깊이 우선 탐색(DFS) 방식으로 자식 컴포넌트의 souldComponentUpdate함수와 render 함수를 실행시킵니다. 역시 true라면 리렌더되고 false라면 리렌더되지 않겠죠?

 

 3. 이런식으로 얻은 새로운 Virtaul DOM은 실제 DOM과 동기화되어 있는 기존의 Virtual DOM과 비교하여 변경 사항을 파악 하여 실제로 변경된 부분만 DOM API를 호출하여 DOM에 반영하게 됩니다. 

 

 4. 브라우저는 새롭게 변경된 DOM과 CSSOM을 결합하여 Render tree를 생성하여 화면에 페인팅합니다. 

 

 

 간단히 말하자면, Virtual DOM 트리를 사용해서 이전 상태와 이후 상태를 비교하여, 바뀐 부분을 찾아내서 자동으로 바뀌게 한다고 할 수 있습니다. 

 

 

 

 

[ 또 다른 문제점 ]

 

 Virtual DOM을 사용한다고 해서 모든 프로세스가 효율적으로 돌아가는 것은 아닙니다. 

 

 예를 들어, 컴포넌트 내부에서 딱 한 번만 연산해놓으면 되는 함수가 있다고 가정해봅시다.

 

 만약 이 컴포넌트의 상태가 변화하면 이 함수 역시 재 연산을 수행하게 되어 역시 비효율적이겠죠?

 

 이외에도 컴포넌트 내부에서 발생할 수 있는 문제점은 여러가지가 있습니다. 

 

 이때 사용할 수 있는 것이 useRef, useCallback, React.memo 등이 있는데 이것들은 따로 포스팅하겠습니다. 

반응형