React와 Virtual DOM

mia·2023년 4월 7일
0

Virtual DOM의 탄생 배경

DOM(Document Object Model)이란..?

DOM은 웹 페이지를 이루는 HTML 태그들을 자바스크립트가 이용할 수 있게 브라우저가 트리구조로 만든 객체 모델을 의미한다.

DOM Tree 안에는 각각의 element에 상응하는 node들이 들어있다. DOM이 제공하는 API를 사용하여 돔 구조에 접근하여 원하는 element의 구조, 스타일 등을 변경할 수 있다. 이러한 행위를 DOM 조작이라고 하며 JavaScript의 getElementById()나 querySelector()와 같은 API가 이 역할을 한다.
즉, DOM은 HTML과 스크립팅 언어(JavaScript)를 서로 이어주는 역할을 하는 것이다.

Virtual DOM(가상 돔)이 나오게 된 이유

큰 규모의 웹 애플리케이션은 엄청난 양의 데이터를 가지고 있으며 각 데이터를 표현하는 요소의 갯수도 규모가 크다. 이 각각의 요소에 접근하기 위해 DOM에 직접 접근하게된다면 성능 이슈가 발생하기 시작한다.
DOM 자체는 빠르기 때문에 읽고 쓸 때의 성능은 자바스크립트 객체를 처리할 때의 성능과 비교하여 다르지 않다.
단, 웹 브라우저 단에서 DOM 변화가 일어날 때마다 웹 브라우저가 CSS를 다시 연산하고 레이아웃을 구성하고, 페이지를 리페인팅하는 과정에서 시간이 허비된다.
이를 개선하기 위해 가상 돔이 나오게 되었다.

Virtual DOM

Virtual DOM이란..?

Virtual DOM은 실제 DOM과 같은 내용을 담고 있는 복사본이다. 그리고 이 복사본은 자바스크립트 객체 형태로 메모리 상에 저장되어있다.
Virtual DOM은 HTML 객체에 기반한 자바스크립트 객체로 표현할 수 있다. 이는 실제 DOM이 아닌 메모리 상에서 동작하며 class, style등의 속성은 가지고 있지만 직접 렌더링을 시키는 DOM api 메서드는 가지고 있지 않아 가볍다.

Virtual DOM의 동작 원리

<ul id="items">
	<li>Item 1</li>
	<li>Item 2</li>
</ul>

👇  HTML을 자바스크립트 객체로 표현했을 때 👇

let domNode = {
	tagName: 'ul',
	attributes: { id: 'items' },
	children: [
		{
			tagName: 'li',
			textContent: 'Item 1',
		},
		{
			tagName: 'li',
			textContent: 'Item 2',
		},
	],
};

이처럼 Virtual DOM은 HTML을 객체형식으로 가지고 있다.
가상 돔은 변경이 있을때마다 렌더링 하지 않으며 모든 변경이나 업데이트가 모두 마무리 된 이후 한번에 실제 DOM이 이 결과를 업데이트한다.

React가 Virtual DOM을 반영하는 절차

ex) 특정 페이지에서 데이터가 변했다고 가정했을 경우.

  • 리액트를 이용해 돔을 업데이트 시키는 절차
  1. 데이터가 업데이트 되면, 전체 UI를 Virtual DOM에 리렌더링함.(모든 React DOM object는 그에 대응하는 virtual DOM object가 있다.)
  2. 데이터의 변동이 일어나면 Virtual DOM과 업데이트 이전의 Virtual DOM 스냅샷을 비교하여 어떤 Virtual DOM이 바뀌었는지 검사한다. (가상 돔끼리 비교)
  3. Diffing 알고리즘을 이용하여 바뀐 내용만 업데이트 한다.
  4. 변경이나 업데이트가 모두 마무리 된 이후에 실제 DOM에서 이 결과를 한번에 업데이트 한다.

React Fiber

Fiber는 컴포넌트 및 컴포넌트의 입력과 출력에 대한 정보를 포함한 자바스크립트 객체이다.
즉, React Element를 객체형식으로 바꾸어 놓은 것이다.

const element = {
	type: 'hi',
  	props: {
    	title: 'foo',
      	children: 'hello',
    },
};

Diffing 알고리즘

모든 React DOM object는 그에 대응하는 virtual DOM object가 있다. = fiber
상황에 따라 두가지로 나뉜다.

  • element의 속성 값만 변한 경우(type === type) : 속성 값만 업데이트
  • element의 태그 또는 컴포넌트가 변경된 경우(type !== type) : 해당 노드를 포함한 하위 노드를 unmount(제거) 후 새로운 virtual DOM으로 대체

Batch Update

변경된 모든 element들을 집단으로 실제 돔에 한번에 적용시켜주는 것

Reconsiliation(재조정)

Diffing을 통해 변경된 부분을 파악한 이후, 리액트는 Batch Update를 수행함으로 실제 DOM에 한번에 적용시켜준다. 이러한 과정을 재조정, Reconsiliation이라고 한다.

재조정과 'key'prop

React element가 변화할때, 재조정 과정에서 이전의 Virtual DOM과 새로 생성된 Virtual DOM을 비교한다.

<ul>
  <li>first</li>
  <li>second</li>
</ul>
// after
<ul>
	<li>first</li>
	<li>second</li>
	<li>third</li>
</ul>

위와 같이 li요소가 밑에 새롭게 추가되는 경우는 문제가 되지 않는다.

<ul>
	<li>first</li>
	<li>second</li>
</ul>
// after
<ul>
	<li>third</li>
	<li>first</li>
	<li>second</li>
</ul>

위와 같이 새로운 li요소가 첫번째 위치에 추가된다면 React는 li 요소 전체가 바뀐 것으로 판단하여 ul의 자식 노드를 새로 그리게 된다. 👉 성능 문제 발생!!
이때 자식 노드들이 key값을 가지고 있을 경우 react는 이전 tree와 새로운 tree를 key값으로 비교하게 된다. key값이 있다면 위의 문제처럼 첫번째 위치에 요소가 추가되더라도 문제없이 새로운 요소만 추가할 것이다.
따라서 key값으로는 변경되지 않는 유일한 값을 사용해야하며 배열의 index를 사용하는것은 배열이 바뀔 때마다 key값이 바뀌기 때문에 key값으로 사용하는 것을 지양해야만 한다.

profile
노 포기 킾고잉

0개의 댓글