React 가 Virtual DOM 을 사용하는 이유

우현민·2022년 2월 22일
25

React

목록 보기
1/11
post-thumbnail

React 를 공부할 때 맨 처음 나오는 개념들 중 Virtual DOM 이라는 친구가 있습니다. 많은 자료들에서 Virtual DOM이 성능이 좋고 그런 이야기를 하는데, 이게 진짜인지, 정확히 어떤 말인지 알아보겠습니다.

DOM 이란?

DOM (Document Object Model) 은 HTML / XML 문서에 접근하기 위한 인터페이스입니다. 브라우저는 HTML 문서를 파싱하여 사용자에게 시각화해 줍니다. 이때 우리는 여러 가지 이유로 브라우저가 띄워주는 HTML 문서에 어떤 동적 처리를 해 주고 싶을 텐데, 그 과정을 도와주는 인터페이스가 DOM입니다. 대표적인 DOM 규격 중 하나인 W3C DOM의 API DOC 을 보면 우리가 흔히 아는 getElementsByTagName 과 같은 메소드를 정의하고 있음을 알 수 있습니다.

프로그래머가 DOM을 이용하는 법

JavaScript 는 브라우저에서 Web API를 이용하고 DOM을 조작하기 위해 태어난 언어입니다. 따라서 DOM을 조작하기 위해서는 JavaScript를 이용합니다.

// js
function addItem () {
  const value = document.getElementById('input').value;
  const list = document.getElemendById('list');
  const newItem = document.createElement('li');
  const text = document.createTextNode(value);
  
  newItem.appendChild(text);
  list.appendChild(newItem);
}

// html
...
<ul id="list">
  <li>a</li>
  <li>b</li>
</ul>
<input id="input"></input>
<button onclick="addItem">+</button>
...

우리는 위와 같이 JavaScript를 통해 DOM을 조작할 수 있었습니다.

관용적으로 "DOM을 조작한다"라는 표현이 이용되긴 하지만, DOM은 인터페이스이고 개발자가 조작하고 싶은 건 화면이기 때문에 DOM을 조작한다는 표현이 개인적으로는 조금 어색하게 느껴집니다. 아마 DOM을 이용한다 정도가 정확한 표현일 것 같습니다.



Virtual DOM 의 탄생

Web의 복잡도가 점차 증가했고 DOM 조작이 점점 빈번하게 일어나게 되었습니다. 브라우저 렌더 과정 에 따라 DOM의 조작은 브라우저 렌더 과정을 유발합니다. (렌더 트리 생성, 페인트 등등) 그러니까 3000번의 변화가 생기면 렌더도 3000번 진행한다는 거죠.

DOM 조작이 많이 발생할 경우, 이는 상당히 비효율적입니다. Virtual DOM 은 이런 상황을 해결하기 위해 탄생했습니다.

Virtual DOM은 하나의 가상 레이어입니다. Virtual DOM에 적용하는 변경사항은 DOM에 바로 반영되지 않습니다. 다만 그 변경사항들을 모아뒀다가, 한번에 DOM한테 보냅니다. 그러면 DOM은 업데이트를 딱 한 번만 하면 되고, 그러면 렌더도 한 번만 하면 되는 거죠. DOM에 들어온 조작은 딱 한 번이니까요! 따라서 DOM 조작이 아주 빈번할 경우 Virtual DOM은 DOM을 조작하는 것에 비해 효율적으로 동작합니다.

그런데 여기, 함정이 있습니다.

Virtual DOM의 작동 원리는 하나의 레이어를 더 거쳐가는 동작이기 때문에, DOM 조작이 아주 많지 않다면 "당연하게도" DOM을 직접 조작하는 것보다 느립니다.

  • Virtual DOM을 조작하고 -> DOM을 조작하는 것
  • DOM을 조작하는 것

당연히 전자가 느리겠죠?

그리고 실제로 DOM 조작은 그리 드라마틱하게 많이 발생하지 않습니다. 정상적인 상황에서 3000번의 DOM 조작 같은 건 일어날 일이 없습니다.

그러니까 사실 대부분의 상황에서 웹 개발자들은 Virtual DOM 을 이용할 필요가 없습니다. 그렇게까지 안 해도 충분히 잘 돌아가거든요!



React 의 탄생

그런데 어느 날 이 Virtual DOM 의 대유행을 유발하는 한 라이브러리가 등장합니다.

Facebook 에서는 프론트엔드 MVC패턴을 사용하고 있었습니다. Facebook 에는 페이스북 메시지가 오지 않았는데 메시지가 와 있다고 뜨는 심각한 버그가 있었고, 이들은 그 버그를 해결하지 못했습니다.

데이터 흐름을 파악하고 버그를 체크하는 데에 신물이 난 이들은 아예 새로운 발상을 하게 됩니다.

그냥 데이터가 바뀌면 싹 다 다시 그려 버리면 안돼?

그러니까, DOM에 변경사항을 조작해서 집어넣지 말고 그냥 데이터가 바뀔 때마다 전부 다 다시 그려 버리면 버그가 생길 일이 없지 않냐는 질문이었습니다. (필자는 이게 React의 핵심 아이디어라고 생각합니다)

옛날이었으면 말도 안 되는 발상이었겠죠? 업데이트될 때마다 DOM에다가 수많은 조작을 가해야 할 테니까요. 하지만 이때 세상에는 Virtual DOM 이라는 기술이 있었습니다. 앞서 말했듯이 "DOM 조작이 드라마틱하게 많이 발생한다면" Virtual DOM이 충분한 가치를 지닙니다. 조금 더 구체화된 아이디어는 다음과 같습니다.

전부 다 Virtual DOM 에 새로 그리고, 기존에 비해 변경된 부분만 DOM에 한 번에 보내버리면 되지 않을까?

상당히 막무가내인 방식이었으나 결국 React 는 성공했습니다. React를 이용하면 데이터 흐름과 DOM의 차이에 의한 버그가 발생하지 않았고, 코드를 선언적으로 깔끔하게 작성할 수 있었습니다.

const [value, setValue] = useState('');
const [list, setList] = useState(['a', 'b', 'c']);

const handleChange = (e) => {
  setValue(e.target.value);
}

const handleClick = () => {
  setList([ ...list, value ]);
}

return (
  <>
    <ul>
      {list.map((item, i) => <li key={i}>{item}</li>}
    </ul>
    <input value={value} onChange={handleChange />
    <button onClick={handleClick}>+</button>
  </>
)

react 코드. 데이터 바인딩이니 흐름이니 하나도 신경 쓸 필요 없고, 상태에만 집중하여 선언적인 코드를 짤 수 있다.



흔한 오해

대부분의 상황에서 Virtual DOM은 빠르지 않습니다.

Virtual DOM을 이용하겠다는 건 데이터를 한번 조작하고, DOM을 또 한 번 조작하겠다는 이야기입니다. 당연히 DOM을 바로 조작하는 것보다 느립니다.

다만 극소수의 상황에서 (react가 이용하는) DOM 조작이 너무 빈번하게 일어날 경우, Virtual DOM을 이용해서 업데이트를 모아서 한번에 DOM한테 보내는 게 더 효율적이어집니다.

React 도 빠르지 않습니다.

프론트엔드 프레임워크 TTI 비교

이미지 출처: levelup.gitconnected.com

측정 방식에 따라 다르겠으나 위 사진에서 볼 수 있다시피 React 는 성능이 좋은 라이브러리가 아닙니다. 거의 가장 느린 프레임워크들과 어깨를 나란히 합니다. "데이터가 바뀌면 싹 다 다시 그리겠다"는 우직한 철학 때문입니다. 어마어마한 양의 DOM 조작을 감당하기 위해 Virtual DOM 을 차용했고, "봐 줄 만한 수준"의 성능이 나오는 라이브러리가 된 것일 뿐 성능이 좋지는 않습니다.

성능은 높을수록 좋은 거 아니냐고요? 사실 프론트엔드에서는 "봐 줄 만한 수준" 만 되면 (16.6ms 이내) 됩니다. 어차피 브라우저는 대부분 60fps거든요!

Myth: React is “faster than DOM”.
Reality: it helps create maintainable applications, and is fast enough for most use cases.

- Dan Abramov on twitter



요약 및 결론

Virtual DOM은 DOM을 직접 조작하지 않고 변경사항을 하나의 가상 돔에 모았다가 DOM에 한 번에 보내는 기술입니다.

일반적인 상황에서 웹의 복잡도가 높다 해도 Virtual DOM을 사용할 이유는 거의 없었습니다. 아이디어는 괜찮지만 실제로 Virtual DOM이 더 중요할 만한 상황이 없었고, 그게 오히려 느렸거든요.

React 의 근본 아이디어는 "다 다시 그려버리겠다"는 것으로 Virtual DOM이 충분한 의미를 가질 만한 무식한 양의 DOM 조작을 요구했습니다.

결국 React 는 Virtual DOM을 통해 대부분의 상황에서 봐 줄 만한 성능을 보여주는 라이브러리가 되었고, 성능을 포기하면서 챙긴 철학을 통해 글을 작성하는 시점 기준 세상에서 가장 인기있는 프론트엔드 툴이 되었습니다.



참고자료

profile
프론트엔드 개발자입니다

5개의 댓글

comment-user-thumbnail
2022년 6월 25일

"그러니까, DOM에 변경사항을 조작해서 집어넣지 말고 그냥 데이터가 바뀔 때마다 전부 다 다시 그려 버리면 버그가 생길 일이 없지 않냐는 질문이었습니다." 라는 말씀이 굉장히 와닿습니다. 좋은 글 잘 읽고 갑니다. 🙂

1개의 답글
comment-user-thumbnail
2022년 11월 9일

Virtual DOM이 무엇인지 이해가 슉슉 되네요. 잘 읽고 갑니다 :)

1개의 답글
comment-user-thumbnail
2023년 9월 7일

이해하기 쉽게 설명을 풀어주셔서 도움 받고 갑니다. 감사합니다. 😀

답글 달기