1. VDOM의 정의
리액트 legacy 공식문서(https://ko.legacy.reactjs.org/docs/faq-internals.html)에 따르면 VDOM을 다음과같이 정의하고 있습니다.
Virtual DOM (VDOM)은 UI의 이상적인 또는 “가상”적인 표현을 메모리에 저장하고 ReactDOM과 같은 라이브러리에 의해 “실제” DOM과 동기화하는 프로그래밍 개념입니다. 이 과정을 재조정이라고 합니다.
브라우저의 크리티컬 렌더링 패스 수행은 꽤나 무거운 작업입니다. 따라서 보여져야할 모든 UI정보를 메모리상의 자바스크립트 객체로 저장하고, 변경사항을 관리하며, 최적의 브라우저 렌더링을 수행할 수 있는 상태로 커밋하여 UX를 높이는 기술이라 할 수 있습니다.
2. VDOM의 구성요소
VDOM의 구성요소를 알기위해서는 다음의 두 개념을 인지하고 있어야 합니다.
- React Element
- Fiber
2.1 React Element
React Element는 JSX표현으로 작성된 요소(JSX Element)를 리액트가 관리할 수 있는 형태의 자바스크립트 객체로 변환한 요소를 말합니다.
리액트는 빌드시 다음과 같은 JSX Element를 React Element생성 함수 호출 표현식으로 트랜스파일합니다.
JAVASCRIPT
// JSX 엘리먼트
const element = <div className="container">Hello</div>;
// 트랜스파일 후 - React.createElement() 호출 // 17버전 이후 _jsx 함수 호출로 변경
const element = React.createElement(
'div',
{ className: 'container' },
'Hello'
);
React Element는 리액트가 관리할 UI의 기본요소라고 할 수 있는데요,
다음과 같은 형태를 갖습니다.
YAML
// React Element의 기본 구조
const element = {
$$typeof: Symbol.for('react.element'),
type: 'div',
key: null,
ref: null,
props: {
children: 'Hello World', (자식요소가 여러개일 경우 배열 형태로 존재)
className: 'greeting'
// 기타 속성들
},
_owner: null
};
여기서 주목해볼만한 속성은 type, key ,props 입니다.
- type은 리액트가 호스트컴포넌트(’div’, ‘span’등의 html태그) 인지, 리액트의 함수 또는 클래스 컴포넌트인지에 대한 정보가 할당
- key는 리액트가 리스트를 렌더링할 때 식별하기 위한 고유값
- props로는 해당 엘리먼트의 모든 속성(attribute)값과 children을 포함
리액트는 VDOM을 구성하기 위해 위와같은 React Element객체를 기반으로 다음과 같은Fiber객체를 만듭니다.
DTS
// Fiber 노드의 기본 구조
const fiber = {
// 태그(숫자) - 파이버의 종류를 식별 (함수형/클래스형 컴포넌트, 호스트 컴포넌트 등)
tag: WorkTag, // ex tag: FunctionComponent, // 0
// 해당 엘리먼트의 고유 식별자
key: null | string,
// 요소의 타입 (div, span, 컴포넌트 함수/클래스 등)
elementType: any, // elementType: 'h1'
// DOM 노드나 컴포넌트 인스턴스와 같은 실제 노드를 참조
stateNode: any,
// Fiber 트리 구조를 구성하는 참조 링크들
return: Fiber | null, // 부모 Fiber
child: Fiber | null, // 첫번째 자식 Fiber
sibling: Fiber | null, // 다음 형제 Fiber
index: number, // 형제들 사이에서의 인덱스
// 작업 관련 정보
pendingProps: any, // 처리해야 할 새로운 props
memoizedProps: any, // 이전에 처리된 props
updateQueue: Queue, // 상태 업데이트 큐
memoizedState: any, // 이전 상태 값
// 사이드 이펙트 관련
flags: Flags, // 수행해야 할 작업 종류 (생성,수정,삭제 등)
subtreeFlags: Flags, // 자식들의 사이드 이펙트 플래그
deletions: Array<Fiber> | null, // 삭제될 자식들
// 작업 우선순위 관련
lanes: Lanes, // 이 Fiber의 우선순위
childLanes: Lanes, // 자식들의 우선순위
// 대체 Fiber (더블 버퍼링용)
alternate: Fiber | null // workInProgress <-> current 전환용
};
Fiber객체는 React Element의 정보와 더불어 리액트의 상태관리 시스템과 연동될 중요한 정보들을 갖게 됩니다.
- 엘리먼트타입
- Hook 관련 정보
- 사이드 이펙트 관련 정보
- 우선순위 관련 (동시성 렌더링)
- 부모,자식,형제 Fiber 참조
- alternate: 작업중인 파이버 노드의 참조
우리는 위 Fiber객체의 내부 형태로부터 미루어보아 리액트가 Fiber 객체의 내부 속성을 기반으로 상태를 관리할 수 있다는 것을 알 수 있습니다.
3. VDOM의 구조
3.1 렌더링의 시작
REASONML
// React 18 이후 (New) // 동시성 렌더링 모드 실행
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />);
위와 같이 리액트는 루트 컴포넌트를 렌더하는 함수를 시작점으로 Fiber 트리의 확장을 수행합니다.
3.2 더블버퍼링 형태의 VDOM구조

App컴포넌트의 렌더는, 처음으로 전체 컴포넌트 트리를 파이버트리로 확장하는 작업의 수행을 의미합니다.
- 파이버트리는 current, workInProgress 파이버 트리로 구성되며, workInProgress는 current를 자가복제한 파이버트리
리액트는 현재 DOM을 표현하는 Current 트리와, 작업중인 WorkInProgress 트리를 기반으로 더블 버퍼링 구조를 유지하므로써 최적화된 diffing작업을 수행하게 됩니다.
리액트가 VDOM을 위와같은 더블 버퍼링형태로 유지하는 이유는 다음과 같습니다.
- 현재 화면에 표시되는 UI를 담당하는 Current 트리를 안정적으로 유지
- 업데이트를 위한 새로운 UI 계산은 WorkInProgress 트리에서 수행하여 사용자에게 불완전한 UI가 보이는 것을 방지
- 필요한 경우 렌더링을 중단하거나 우선순위를 조정
1. VDOM의 정의
리액트 legacy 공식문서(https://ko.legacy.reactjs.org/docs/faq-internals.html)에 따르면 VDOM을 다음과같이 정의하고 있습니다.
Virtual DOM (VDOM)은 UI의 이상적인 또는 “가상”적인 표현을 메모리에 저장하고 ReactDOM과 같은 라이브러리에 의해 “실제” DOM과 동기화하는 프로그래밍 개념입니다. 이 과정을 재조정이라고 합니다.
브라우저의 크리티컬 렌더링 패스 수행은 꽤나 무거운 작업입니다. 따라서 보여져야할 모든 UI정보를 메모리상의 자바스크립트 객체로 저장하고, 변경사항을 관리하며, 최적의 브라우저 렌더링을 수행할 수 있는 상태로 커밋하여 UX를 높이는 기술이라 할 수 있습니다.
2. VDOM의 구성요소
VDOM의 구성요소를 알기위해서는 다음의 두 개념을 인지하고 있어야 합니다.
- React Element
- Fiber
2.1 React Element
React Element는 JSX표현으로 작성된 요소(JSX Element)를 리액트가 관리할 수 있는 형태의 자바스크립트 객체로 변환한 요소를 말합니다.
리액트는 빌드시 다음과 같은 JSX Element를 React Element생성 함수 호출 표현식으로 트랜스파일합니다.
JAVASCRIPT
// JSX 엘리먼트
const element = <div className="container">Hello</div>;
// 트랜스파일 후 - React.createElement() 호출 // 17버전 이후 _jsx 함수 호출로 변경
const element = React.createElement(
'div',
{ className: 'container' },
'Hello'
);
React Element는 리액트가 관리할 UI의 기본요소라고 할 수 있는데요,
다음과 같은 형태를 갖습니다.
YAML
// React Element의 기본 구조
const element = {
$$typeof: Symbol.for('react.element'),
type: 'div',
key: null,
ref: null,
props: {
children: 'Hello World', (자식요소가 여러개일 경우 배열 형태로 존재)
className: 'greeting'
// 기타 속성들
},
_owner: null
};
여기서 주목해볼만한 속성은 type, key ,props 입니다.
- type은 리액트가 호스트컴포넌트(’div’, ‘span’등의 html태그) 인지, 리액트의 함수 또는 클래스 컴포넌트인지에 대한 정보가 할당
- key는 리액트가 리스트를 렌더링할 때 식별하기 위한 고유값
- props로는 해당 엘리먼트의 모든 속성(attribute)값과 children을 포함
리액트는 VDOM을 구성하기 위해 위와같은 React Element객체를 기반으로 다음과 같은Fiber객체를 만듭니다.
DTS
// Fiber 노드의 기본 구조
const fiber = {
// 태그(숫자) - 파이버의 종류를 식별 (함수형/클래스형 컴포넌트, 호스트 컴포넌트 등)
tag: WorkTag, // ex tag: FunctionComponent, // 0
// 해당 엘리먼트의 고유 식별자
key: null | string,
// 요소의 타입 (div, span, 컴포넌트 함수/클래스 등)
elementType: any, // elementType: 'h1'
// DOM 노드나 컴포넌트 인스턴스와 같은 실제 노드를 참조
stateNode: any,
// Fiber 트리 구조를 구성하는 참조 링크들
return: Fiber | null, // 부모 Fiber
child: Fiber | null, // 첫번째 자식 Fiber
sibling: Fiber | null, // 다음 형제 Fiber
index: number, // 형제들 사이에서의 인덱스
// 작업 관련 정보
pendingProps: any, // 처리해야 할 새로운 props
memoizedProps: any, // 이전에 처리된 props
updateQueue: Queue, // 상태 업데이트 큐
memoizedState: any, // 이전 상태 값
// 사이드 이펙트 관련
flags: Flags, // 수행해야 할 작업 종류 (생성,수정,삭제 등)
subtreeFlags: Flags, // 자식들의 사이드 이펙트 플래그
deletions: Array<Fiber> | null, // 삭제될 자식들
// 작업 우선순위 관련
lanes: Lanes, // 이 Fiber의 우선순위
childLanes: Lanes, // 자식들의 우선순위
// 대체 Fiber (더블 버퍼링용)
alternate: Fiber | null // workInProgress <-> current 전환용
};
Fiber객체는 React Element의 정보와 더불어 리액트의 상태관리 시스템과 연동될 중요한 정보들을 갖게 됩니다.
- 엘리먼트타입
- Hook 관련 정보
- 사이드 이펙트 관련 정보
- 우선순위 관련 (동시성 렌더링)
- 부모,자식,형제 Fiber 참조
- alternate: 작업중인 파이버 노드의 참조
우리는 위 Fiber객체의 내부 형태로부터 미루어보아 리액트가 Fiber 객체의 내부 속성을 기반으로 상태를 관리할 수 있다는 것을 알 수 있습니다.
3. VDOM의 구조
3.1 렌더링의 시작
REASONML
// React 18 이후 (New) // 동시성 렌더링 모드 실행
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />);
위와 같이 리액트는 루트 컴포넌트를 렌더하는 함수를 시작점으로 Fiber 트리의 확장을 수행합니다.
3.2 더블버퍼링 형태의 VDOM구조

App컴포넌트의 렌더는, 처음으로 전체 컴포넌트 트리를 파이버트리로 확장하는 작업의 수행을 의미합니다.
- 파이버트리는 current, workInProgress 파이버 트리로 구성되며, workInProgress는 current를 자가복제한 파이버트리
리액트는 현재 DOM을 표현하는 Current 트리와, 작업중인 WorkInProgress 트리를 기반으로 더블 버퍼링 구조를 유지하므로써 최적화된 diffing작업을 수행하게 됩니다.
리액트가 VDOM을 위와같은 더블 버퍼링형태로 유지하는 이유는 다음과 같습니다.
- 현재 화면에 표시되는 UI를 담당하는 Current 트리를 안정적으로 유지
- 업데이트를 위한 새로운 UI 계산은 WorkInProgress 트리에서 수행하여 사용자에게 불완전한 UI가 보이는 것을 방지
- 필요한 경우 렌더링을 중단하거나 우선순위를 조정