참고자료

프레임워크 없는 프론트엔드 개발 - 예스24

Vanilla Javascript로 가상돔(VirtualDOM) 만들기 | 개발자 황준일

[번역] 리액트에 대해서 그 누구도 제대로 설명하기 어려운 것 - 왜 Virtual DOM 인가?

1. VirtualDOM

DOM을 추상화한 Object가 VirtualDOM 입니다. 조금 더 쉽게 말해서 “DOM 처럼 생긴 객체”가 바로 가상돔입니다.

이런 HTML이 있습니다.

<div id="app">
  <ul>
    <li>
      <input type="checkbox" class="toggle" />
      todo list item 1
      <button class="remove">삭제</button>
    </li>
    <li class="completed">
      <input type="checkbox" class="toggle" checked />
      todo list item 2
      <button class="remove">삭제</button>
    </li>
  </ul>
  <form>
    <input type="text" />
    <button type="submit">추가</button>
  </form>
</div>

이를 가상돔으로 표현하면 다음과 같습니다.

function virtualDom(type, props, ...children) {
  return { type, props, children: children.flat() }
}

const result = (
	virtualDom('div', { id: 'app' },
	  virtualDom('ul', null,
	    virtualDom('li', null,
	      virtualDom('input', { type: 'checkbox', className: 'toggle' }),
	      'todo list item 1',
	      virtualDom('button', { className: 'remove' }, '삭제')
	    ),
	    virtualDom('li', { className: 'completed' },
	      virtualDom('input', { type: 'checkbox', className: 'toggle', checked: true }),
	      'todo list item 2',
	      virtualDom('button', { className: 'remove' }, '삭제')
	    ),
	  ),
	  virtualDom('form',
	    virtualDom('input', { type: 'text' }),
	    virtualDom('button', { type: 'submit' }, '추가'),
	  )
	)
);

보통 virtualDom 대신 h 로 표현합니다.

function h(type, props, ...children) {
  return { type, props, children: children.flat() }
}

const result = (
	h('div', { id: 'app' },
	  h('ul', null,
	    h('li', null,
	      h('input', { type: 'checkbox', className: 'toggle' }),
	      'todo list item 1',
	      h('button', { className: 'remove' }, '삭제')
	    ),
	    h('li', { className: 'completed' },
	      h('input', { type: 'checkbox', className: 'toggle', checked: true }),
	      'todo list item 2',
	      h('button', { className: 'remove' }, '삭제')
	    ),
	  ),
	  h('form',
	    h('input', { type: 'text' }),
	    h('button', { type: 'submit' }, '추가'),
	  )
	)
);

그리고 위의 코드는 다음과 같은 객체로 변환답니다.

{
  "type": "div",
  "props": { "id": "app" },
  "children": [
    {
      "type": "ul",
      "props": null,
      "children": [
        {
          "type": "li",
          "props": null,
          "children": [
            {
              "type": "input",
              "props": { "type": "checkbox", "className": "toggle" },
              "children": []
            },
            "todo list item 1",
            {
              "type": "button",
              "props": { "className": "remove" },
              "children": [ "삭제" ]
            }
          ]
        },
        {
          "type": "li",
          "props": { "className": "completed" },
          "children": [
            {
              "type": "input",
              "props": { "type": "checkbox", "className": "toggle", "checked": true },
              "children": []
            },
            "todo list item 2",
            {
              "type": "button",
              "props": { "className": "remove" },
              "children": [ "삭제" ]
            }
          ]
        }
      ]
    },
    {
      "type": "form",
      "props": {
        "type": "input",
        "props": { "type": "text" },
        "children": []
      },
      "children": [
        {
          "type": "button",
          "props": { "type": "submit" },
          "children": [ "추가" ]
        }
      ]
    }
  ]
}

코드를 보면 알겠지만, 가상돔(VirtualDOM)은 거창한게 아니라 DOM의 형태를 본따 만든 객체 덩어리입니다. 사실 가상돔(VirtualDOM)만 쓴다고해서 드라마틱한 변화가 생기는 것은 아닙니다.