Virtual DOM

Happhee·2022년 3월 5일
0

💙  React 💙

목록 보기
2/18
post-thumbnail

Virtual DOM은 애플리케이션의 UI를 구성하는 HTML 엘리먼트를 메모리 내에서 구현한 것이다.

컴포넌트가 다시 렌더링될 때, virtual DOM은 업데이트할 요소의 목록을 만들기 위해 기존의 DOM 모델에서 변경되는 사항을 비교하며 DOM 전체를 다시 렌더링할 필요 없이 실제 DOM에 필요한 최소한만 변경하여 효율성이 높다는 것이 큰 장점이다


DOM

Document Object Model 의 약자로 HTML, XML document와 상호작용하고 표현하는 API로 볼 수 있다

Document는 HTML, XML을 말하며, Object는 노드 트리인 것이다.

DOM은 브라우저에서 로드되는 것이며, DOM을 자바스크립트로 노드 추가, 삭제, 변경, 이벤트 처리, 수정 등을 가능하게 하는 것을 말하는 것이다

즉, DOM은 HTML과 자바스크립트를 이어주는 공간이며, 내가 작성한 HTML을 자바스크립트가 이해할 수 있도록 객체로 변환하는 것이다.

또한, DOM안에는 각종 node들이 트리 구조로 들어있기에 DOM을 DOM 트리라고 부르기도 한다

  • node
    모든 HTML Element들은 기본적으로 다 노드이다
  • node의 기능
    textContent, cloneNode 등등이 모두 노드의 기능
    EventTarget이기에 addEventListener

브라우저는 DOM 트리와 CSSOM 트리를 융합한 렌더링 트리로 우리가 보는 화면을 제공한다


브라우저 동작 원리

  1. HTML 파일과 CSS 파일을 파싱해서 각각 Tree를 만든다. (Parsing)
  2. 두 Tree를 결합하여 Rendering Tree를 만든다. (Style)
  3. Rendering Tree에서 각 노드의 위치와 크기를 계산한다. (Layout)
  4. 계산된 값을 이용해 각 노드를 화면상의 실제 픽셀로 변환하고, 레이어를 만든다. (Paint)
  5. 레이어를 합성하여 실제 화면에 나타낸다. (Composite)

자세한 내용은 모던자바 - 38장 브라우저 렌더링 과정을 참고하길 바란다


Virtual DOM

DOM의 구조만 간결히 흉내낸 자바스크립트 객체이다
이는 수정사항이 여러개 있더라도 단 한번만 렌더링을 일으킨다

실제 DOM은 무거우니까 이 전체를 동작하기 보다는 가상 돔을 만들어서 필요한 부분만 조작하는 것이다


Virtual DOM & React

React는 실제 DOM의 변경 사항을 빠르게 파악하고 반영하기 위해 가상 DOM을 만들어서 관리한다.

왜?

React는 성능 향상을 위해 실제 렌더링된 UI를 내부적으로 JavaScript 객체로 표현된 트리에 따로 관리한다. 왜냐하면 DOM 노드를 생성하고 기존 DOM 노드에 접근하는 것은 느리기 때문이다.

원리

  1. 특정 컴포넌트에서 setState를 호출하여 상태를 변경하면, 해당 컴포넌트의 shouldComponentUpdate함수를 실행

    • true를 반환
      -> render함수를 실행

    • false를 반환
      -> render함수를 실행하지 않고,
      자식 컴포넌트의 shouldComponentUpdate 또한 실행되지 않는다.

  2. 상태가 변했다면 해당 컴포넌트를 기준으로 깊이 우선 탐색을 진행하여 자식 컴포넌트의 shouldComponentUpdate, render함수를 실행

  3. render함수를 실행하여 얻은 새로운 Virtual DOM실제 DOM과 동기화되어 있는 기존 Virtual DOM과 비교해서 변경사항을 파악

  4. 실제로 변경된 부분만 DOM API를 호출하여 DOM에 반영

  5. 브라우저가 변경 사항이 반영된 DOMCSSOM으로 새로운 Render Tree를 생성해 화면을 다시 그림


예제로 살펴보기

  • 모델
{
  subject: 'World'
}
  • HTML 파일
<div>
  <div id="header">
    <h1>Hello, {{state.subject}}!</h1>
    <p>How are you today?</p>
  </div>
</div>

이것이 렌더링 되면 Virtual DOM은 아래처럼 나타난다.

{
  tag: 'div',
  children: [
    {
      tag: 'div',
      attributes: {
        id: 'header'
      },
      children: [
        {
          tag: 'h1',
          children: 'Hello, World!'
        },
        {
          tag: 'p',
          children: 'How are you today?'
        }
      ]
    }
  ]
}

여기서 state.subject를 Mom으로 변경하면

{
  tag: 'div',
  children: [
    {
      tag: 'div',
      attributes: {
        id: 'header'
      },
      children: [
        {
          tag: 'h1',
          children: 'Hello, Mom!' //이 부분이 바뀐다
        },
        {
          tag: 'p',
          children: 'How are you today?'
        }
      ]
    }
  ]
}

이렇게 기존의 트리와 변경된 트리를 비교하여 h1만이 바뀐 것을 식별할 수 있으며, 이 단일 요소만을 업데이트하기에 전체를 조작할 필요또한 사라진 것이다.


결론

작은 규모의 레이아웃(reflow)이 여러번 발생하는 것보다 큰 규모의 레이아웃이 단 한번 발생하는 것은 큰 차이를 나타내므로, 리액트는 얕은 비교와 일괄 돔 업데이트 방식을 이용해 성능을 향상시켰다

profile
즐기면서 정확하게 나아가는 웹프론트엔드 개발자 https://happhee-dev.tistory.com/ 로 이전하였습니다

0개의 댓글