Back to blog
Aug 01, 2024
4 min read

[번역] What is Reconciliation and the Virtual DOM (VDOM)?

Reconciliation and the Virtual DOM

원문 : https://playfulprogramming.com/posts/what-is-reconciliation-and-the-vdom

지난 글에서 React, Angular 또는 Vue와 같은 최신 프론트엔드 프레임워크가 "Reactivity"를 사용하여 자바스크립트 상태를 DOM에 쉽게 동기화하는 방법을 소개했습니다. 그 글의 마지막 부분에서 외부 링크를 통해 이러한 각 프레임워크의 반응성 메커니즘이 내부에서 어떻게 작동하는지에 대해 언급했습니다.

ReactVue와 같은 프레임워크에서 사용하는 메커니즘 중 하나는 가상 DOM(VDOM이라고도 함)이며 "Reconciliation"이라는 프로세스를 사용하여 이 VDOM의 변경 사항을 실제 DOM에 반영합니다. 이것이 실제로 어떻게 작동하는지 살펴봅시다.

1. 가상 돔(VDOM)이란 무엇인가요?

간단히 설명하자면 가상 DOM(VDOM)은 프레임워크에서 작성한 코드를 반영한 것으로, 결국 DOM에 미러링됩니다. 이는 자바스크립트 상태에 대한 업데이트가 반응성(reactivity)을 통해 DOM에 복제되도록 하기 위한 것입니다. 용어가 너무 어렵나요? 문제없습니다. 여기 예시가 있습니다. 약간의 HTML이 있다고 가정해 보겠습니다:

<ul>
	<li><p>One</p></li>
	<li><p>One</p></li>
	<li><p>One</p></li>
</ul>

이렇게 하면 다음과 비슷하게 보이는 DOM 트리가 만들어질 수 있습니다:

DOM의 작동 방식에 대해 다시 한 번 알아보고 싶다면 해당 주제에 대한 포스팅을 참조하세요.

마찬가지로 다음 JSX를 작성하면 됩니다:

const App = () => {
	return (
		<ul>
			<li><p>One</p></li>
			<li><p>One</p></li>
			<li><p>One</p></li>
		</ul>
	)
}

JSX에서 작성한 마크업을 미러링하는 VDOM이 생성됩니다. 그런 다음 이 JSXDOM 자체에 반영됩니다:

이러한 변경 사항이 반영되는 과정을 Reconciliation이라고 합니다.

Reconciliation이란 무엇인가요?

Reconciliation은 3단계 프로세스를 통해 프레임워크의 가상 DOM의 변경 사항을 DOM에 반영하는 과정입니다.

  1. 상태의 변경 사항을 감지하기
  2. 변경 사항을 VDOM에 적용
  3. 변경 사항을 VDOM에서 DOM으로반영(commit)하기

key 속성은 무엇인가요?

이 조정 프로세스는 처음에는 간단해 보이지만 상당히 복잡해질 수 있습니다. 예를 들어 목록을 처리하는 방법을 생각해 보세요: 예시

import { useState } from 'react';

const fakeNames = [
	'Gulgowski',
	'Johnston',
	'Nader',
	'Flatley',
	'Lemke',
	'Stokes',
	'Simonis',
	'Little',
	'Baumbach',
	'Spinka',
];

let id = 0;

function createPerson() {
	return {
		id: ++id,
		name: fakeNames[Math.floor(Math.random() * fakeNames.length)],
	};
}

export default function App() {
	const [list, setList] = useState([
		createPerson(),
		createPerson(),
		createPerson(),
	]);
	
	function addPersonToList() {
		const newList = [...list];
		// 랜덤위치에 new friend 추가
		newList.splice(
			Math.floor(Math.random() * newList.length),
			0,
			createPerson()
		);
		setList(newList);
	}
	
	return (
		<div>
			<h1>My friends</h1>
			<button onClick={addPersonToList}>Add friend</button>
			<ul>
				{list.map((person) => (
					<li>
						<label>
							<div>{person.name} notes</div>
							<input />
						</label>
					</li>
				))}
			</ul>
		</div>
	);
}

여기에서는 친구 목록을 저장하고 사용자가 버튼을 눌러 이 목록에 추가할 수 있도록 하고 있습니다. 친구에 대한 메모를 저장할 수 있는 작은 공간도 있습니다! 하지만 누군가가 목록의 시작 부분에 추가되면 그 메모는 어떻게 되는지 주목하세요:

Little에 대한 노트가 이제 어떻게 엉뚱한 사람에게 할당되었는지 보세요.

React는 목록에서 어떤 요소가 어떤 요소인지 식별할 수 있는 방법이 필요하기 때문입니다. 기본적으로 이것은 목록 항목의 인덱스이므로, 원래 목록의 맨 위에 있던 Little에 대한 노트가 다른 사람이 추가되더라도 여전히 목록의 맨 위에 있는 이유입니다.

이 기본 동작이 없다면 사용자가 목록에 추가할 때마다 기존 항목의 DOM 내용을 다시 렌더링하지 않도록 알 수 없기 때문에 목록 내부의 입력이 모두 사라지게 됩니다:

이 문제를 해결하려면 특별한 key 속성을 사용하여 목록에서 어떤 사용자가 어떤 사용자인지 React에 명시적으로 알려주면 됩니다:

<ul>
    {list.map((person) => (
      <li key={person.id}>
        <label>
          <div>{person.name} notes</div>
          <input />
        </label>
      </li>
    ))}
</ul>

결론

이 시리즈에서는 React반응성(Reactivity)을 처리하는 방법과 가상 DOMreconciliation을 사용해 반응성을 작동시키는 방법을 살펴봤습니다.

이 두 가지가 결합되어 React가 백그라운드에서 작동하는 방식의 토대를 구축합니다. 다음 몇 개의 글에서는 서버 측 렌더링(SSR)과 정적 사이트 생성(SSG)이란 무엇인가?를 시작으로 React가 일반적인 클라이언트 측 렌더링 프로세스를 지나 서버로 점차 진화하는 과정을 살펴보겠습니다.

이 시리즈에서는 결국 React 서버 액션을 심층적으로 사용하는 방법과 React 지식을 활용하여 풀 스택 개발자가 되는 방법을 보여줄 것입니다.