티스토리 뷰

DOM

React의 '가상 DOM(Virtual DOM)'과 '일반 DOM(Document Object Model)'은 웹 페이지 렌더링 방식에서 차이점을 가지고 있다.

 

일반 DOM

DOM은 웹 페이지의 구조를 표현하는 객체 모델로, HTML 문서를 객체 형태로 변환해 자바스크립트로 페이지의 요소를 수정하거나 조작할 수 있게 만든다.

 

브라우저는 DOM을 기반으로 페이지를 그리고, DOM 트리가 변경되면, 브라우저는 전체 페이지를 다시 렌더링하여 변경 사항을 반영한다.

 

가상 DOM

React의 가상 DOM은 React에서 사용하는 메모리 내의 DOM의 복사본이다. 실제 DOM에 접근하기 전 가상 DOM에서 변화를 계산하고, 최적화된 방식으로 실제 DOM을 업데이트 한다.

 

React는 컴포넌트의 상태가 변경되면 가상 DOM에서 변경된 부분만 업데이트한다. 이전 가상 DOM과 새로운 가상 DOM을 비교해서 실제 DOM에 적용해야 할 최소한의 변경 사항을 계산하고, 변경된 부분만 실제 DOM에 적용하여 성능을 최적화한다.

 

성능 차이점

'일반 DOM'의 조작은 비용이 비싸다. DOM의 노드를 추가하거나 삭제할 때마다 브라우저는 전체 DOM 트리를 다시 계산하고 렌더링해야 가능하다. 이로 인해 성능이 저하될 가능성이 있다.

 

'가상 DOM'을 사용하게 되면, 실제 DOM을 직접 조작하지 않고 메모리 내에서만 조작한다. 이로 인해 빠른 렌더링과 성능 향상을 기대할 수 있다.

 

그리고, 업데이트 방식에서 '일반 DOM'은 DOM 노드의 변경은 즉각적으로 적용된다. 페이지의 큰 부분이 업데이트가 되면, 전체 DOM을 다시 렌더링할 수 있다.

 

반대로 '가상 DOM'은 상태 변경이 발생하면 최소한의 업데이트를 수행한다. 변경된 부분만 실제 DOM에 반영하므로, 불필요한 렌더링을 줄일 수 있다.

 

이는 코드에서 확인해볼 수 있다.

 

<!DOCTYPE html>
<html>
<head>
  <title>DOM Example</title>
</head>
<body>
  <div id="container">
    <!-- 콘텐츠 추가 공간 -->
  </div>
  <script>
    const container = document.getElementById('container');

    // 많은 요소를 추가하는 예제
    for (let i = 0; i < 1000; i++) {
      const element = document.createElement('div');
      element.textContent = `Item ${i}`;
      container.appendChild(element);
    }

    // 요소를 수정하는 예제
    for (let i = 0; i < 1000; i++) {
      const element = container.children[i];
      element.textContent = `Updated Item ${i}`;
    }
  </script>
</body>
</html>

 

위 '일반 DOM' 예제에서는 1,000개의 `div` 요소를 생성하고, 이를 `container`에 추가한 뒤, 다시 1,000개의 요소를 수정하는 코드이다. 이 과정에서 브라우저는 DOM 트리를 매 번 다시 계산하고 렌더링 한다.

 

아래는 '가상 DOM' 예제이다.

import React, { useState } from 'react';
import ReactDOM from 'react-dom';

const App = () => {
  const [items, setItems] = useState(Array.from({ length: 1000 }, (_, i) => `Item ${i}`));

  const updateItems = () => {
    setItems(items.map((item, index) => `Updated Item ${index}`));
  };

  return (
    <div>
      <button onClick={updateItems}>Update Items</button>
      <div>
        {items.map((item, index) => <div key={index}>{item}</div>)}
      </div>
    </div>
  );
};

ReactDOM.render(<App />, document.getElementById('root'));

 

위 React 예제는 상태를 사용해 1,000개의 `div` 요소를 렌더링하고 업데이트한다. React는 가상 DOM을 통해 변경된 부분만 실제 DOM에 적용하기 때문에, 불필요한 렌더링을 줄이고 성능을 향상시킬 수 있다.

 

한 가지, React에는 불필요한 렌더링을 방지하기 위해 `useMemo`, `useCallback` 등 메모이제이션 함수를 사용할 때가 있다. 정말 필요한 곳에 사용한다면, 정말 훌륭한 방법이지만, 이를 남용하게 된다면 메모리를 많이 사용하게 되어 오히려 안 좋은 결과를 가져올 수 있다. 그러니, 사용할 때는 유의해서 사용해야 한다.