React 최적화 기법에 관심이 있는 당신, JSX와 VDOM에 대해서는 아시나요?

유소정·2025년 11월 24일

React를 사용한다면 다음과 같이 JSX를 사용해봤을 것입니다.

const element = <h1>Hello, world!</h1>;

JSX로 인해 그동안 편하게 코드를 작성했었죠?
먄약 JSX의 어떤 점이 편했는지 모르겠다면, 이 글을 한 번 읽어보세요! 😊

이 글에서는 JSX와 VDOM에 대해 설명하고 있습니다.
이는 React 최적화 기법을 공부하기 위해서 꼭 알아야 할 지식입니다.

🙋‍ JSX가 뭐예요?

JSX는 XML-like syntax extension to ECMAScript의 약자로, 자바스크립트 확장한 문법입니다. JSX의 형태는 XML과 유사합니다. 예를 들어, <name></name> 이런 형태를 가질 수 있습니다. 위에서 예시로 보여줬던 <h1><h1> 도 마찬가지입니다. 생김새가 XML과 유사하죠?

🙋‍ JSX는 React에서만 써야 돼요?

아니요. JSX는 React에서 쓰지 않아도 됩니다. Vue 같은 라이브러리에서도 사용할 수 있습니다. React의 부산물로 JSX가 탄생했기 때문에 사람들이 종종 이런 오해를 합니다.

🙋‍ JSX는 쓰는 건 필수예요?

아니요. JSX는 필수가 아닙니다. JSX는 자바스크립트 코드와 1:1로 매칭 됩니다. 그럼 JSX를 쓰지 않고 자바스크립트 코드를 써도 된다는 말이 돼죠.

🙋‍ 그럼 JSX는 왜 쓰는 거예요? 그냥 자바스크립트 코드를 써도 되지 않아요?

맞습니다. 자바스크립트 코드를 써도 됩니다. 하지만 JSX를 쓰는 이유는 편해서입니다. JSX코드와 JSX코드를 자바스크립트로 변환한 코드를 비교해보겠습니다.

해당 코드는 Increase라고 적힌 버튼을 클릭했을 때, count 값이 증가하는 증가하는 코드입니다. 한 눈에 봐도 JSX코드가 자바스크립트 코드보다 가독성이 좋고 짧지 않나요? 그래서 JSX를 쓰는 것입니다.

JSX 코드

<div>
	<p>Count: {count}!</p>
	<button type="button" onClick={() => setCount(count + 1)}>Increase</button>
</div>

변환된 JS 코드

React.createElement(
	"div",
	null,
	React.createElement("p", null, "Count: ", count, "!"),
	React.createElement("button", { type: "button", onClick: () => setCount(count + 1) }, "Increase")
);

🙋‍JSX를 어떻게 인식하는 거예요?

컴파일은 JSX가 아닌 자바스크립트만 가능합니다. 그래서 JSX의 XML처럼 작성된 부분분은 자바스크립트 코드로 변환이 돼야 하는데, 이때 Babel이나 Parcel과 같은 변환기를 통해서 자바스크립트로 변환이 됩니다. 이는 React.createElement를 쓰는 자바스크립트 코드로 변환 됩니다.

JSX 코드

<p>Hello, World</p>

자바스크립트로 변환한 코드

React.creteElement("p", null. "Hello, world!");

🙋‍ JSX는 React.createElement를 쓰는 자바스크립트 코드로 변환 되는 군요! React.createElement는 어떤 구조를 가져요?

React.createElement는 다음과 같은 구조를 가집니다. React.createElement(함수, 속성, 자녀) 로 이해하면 됩니다.

React.createElement 구조

React.createElement(
	type,         // 함수
	[props],      // 속성
	[...children] // 자녀
)

JSX 코드랑 비교해서 보면 더 쉽게 이해할 수 있습니다.

JSX 코드

JSX 코드

<div>
	<p>Count: {count}!</p>
	<button type="button" onClick={() => setCount(count + 1)}>Increase</button>
</div>

// 참고로 자녀는 React.Fragment나 div 같은 태그를 이용해서 바깥에서 감싸줘야 하는데, 
// 각 줄을 구분하기 위해서입니다.

변환된 JS 코드

React.createElement(
	"div",
	null,
	React.createElement("p", null, "Count: ", count, "!"),
	React.createElement("button", { type: "button", onClick: () => setCount(count + 1) }, "Increase")
);
 

코드를 자세히 보면서 특징을 파악해봅시다.

변환된 JS 코드의 특징변환된 JS 코드에서 예시
속성과 자녀는 값이 없다면 null값이 들어간다.div태그의 속성이 없어서 null값이 들어갔다.
자녀는 여러 명일 수 있다. 세 번째 인자부터 자녀의 수만큼 열거 된다.div태그의 자녀로 p태그와 button태그가 있다. 이는 세 번째 인자부터 열거됐다.
type을 소문자로 쓰면 HTML 태그로 인식하고, 대문자로 쓰면 Component로 인식한다.div를 소문자로 썼기 때문에 HTML 태그로 인식한다.

🙋‍ 치환된 React.CreateElement는 무엇을 만드는 코드예요?

React.createElement는 VDOM 트리의 React Element를 만드는 코드입니다.

🙋‍ React Element가 뭐예요?

먼저 Element에 대해 설명해드리겠습니다. Element는 트리의 노드입니다. 예를 들어, document.createElement(’div’) 코드는 트리의 노드를 만듭니다. <div></div> 라는 DOM 트리의 노드를 만드는 것입니다. 이걸 DOM 트리의 Element라고도 합니다. 이처럼 React.createElement 코드도 트리의 노드를 만듭니다. VDOM 트리의 노드를 만드는 것입니다. 이를 VDOM 트리의 React Element라고 합니다.

🙋‍ VDOM 트리는 뭐예요?

VDOM은 Virtual DOM입니다.. 이름 그대로 가상의 DOM이라는 뜻입니다. React는 VDOM을 사용하는 게 특징인데요, VDOM은 React Element 노드로 이루어져 있습니다.

🙋‍ VDOM 트리는 무슨 역할을 하는 거예요?

React는 State가 변경되면 리렌더링을 합니다. 그런데 전체를 리렌더링 하는 게 아니라, 변경된 State와 관련된 부분만 업데이트합니다. 다시 말하자면, 변경된 State와 관련이 없는 부분은 리랜더링 하지 않는 것입니다.

이게 가능한 이유는 VDOM 트리가 있기 때문입니다. VDOM 트리는 새로운 React Element로 인해 새롭게 만들어집니다. React는 새로운 VDOM 트리를 DOM 트리와 비교해서 DOM 트리가 업데이트 해야 할 부분을 찾습니다. 그리고 DOM 트리에 찾은 부분을 갱신합니다.

정리하자면, VDOM 트리가 존재하는 이유는 DOM 트리와 비교해서 DOM 트리를 업데이트 하기 위해서입니다. 우리는 이 과정을 재조정이라고 부릅니다. 만약 VDOM 트리가 없다면, 바뀐 요소를 찾지 않고 모든 요소를 DOM 트리에 갱신해서 전체를 리렌더링 하게 됩니다.

재조정을 하기까지의 과정

  1. JSX 작성한 코드는 React.createElement 코드로 변경된다.
  2. React.createElement는 새로운 React Element를 만든다.
  3. 새로운 React Element는 새로운 React Element 트리(VDOM 트리)를 만든다.
  4. VDOM 트리는 DOM 트리를 비교해서 다른 점을 찾는다. (재조정)
  5. 다른 점이 있다면 DOM 트리에 새로운 점을 갱신한다. (재조정)

재조정

🙋‍ VDOM 트리는 왜 쓰는 거예요? React Element로 새로운 DOM 트리를 만들면, 새로운 VDOM 트리 필요없이 DOM 트리에 바로 업데이트가 가능하잖아요? VDOM 트리를 쓰는 이유를 모르겠어요.

😀 VDOM 트리는 충분한 빠르기를 제공한다

질문에 있듯이, VDOM 트리 없이 DOM 트리에 바로 적용하면 더 빠릅니다. 하지만 빠른 속도는 중요하지 않습니다. VDOM 트리를 이용해도 충분히 빠르기 때문입니다.

React가 DOM보다 빠르다는 것은 잘못된 사실이고, 실제로는 유지 보수가 가능한 애플리케이션을 만드는 것을 React가 도와주고 대부분의 경우에서 Virtual DOM은 충분히 빠르다는 것입니다.

By Dan Abramov (Redux의 창시자)

😀 VDOM 트리를 쓰는 이유는 유지보수 때문이다

React는 선언형 UI라는 더 나은 구조를 줍니다. 이게 VDOM 트리를 쓰는 이유입니다. 쉽게 말해보겠습니다. React를 사용하면, JSX로 작성만 해도 새로운 React Element를 생성하고 VDOM에 넣습니다. 그리고 실제 DOM과 재조정도 합니다. 개발자는 JSX 작성만 했는데, 나머지 부분이 알아서 이뤄지는 것입니다. 개발자는 선언만 했는데 UI가 자동으로 업데이트 되는 것입니다. 엄청 편하게 느껴지지 않나요?

만약에 선언형 UI가 아니라고 생각해봅시다. Element 하나를 수정해야 하는데, JQuery를 써서 바꿔야 하는 상황이면, DOM에서 해당 Element를 찾기도 힘들고 변경하는 것도 일이 될 것입니다.

🙋‍ VDOM 트리와 DOM 트리를 같은 구조를 가져요?

아니요. VDOM 트리와 DOM 트리는 같은 구조를 갖지 않습니다. VDOM 트리에는 있는 부분이 DOM 트리에는 없기도 합니다. 예를 들어, React.Fragment는 DOM 트리에는 없습니다.

🙋‍ VDOM 트리와 최적화 기법은 무슨 관계예요?

VDOM 트리는 최적화 기법을 통해 동기화를 최적화 할 수 있습니다. 최적화 기법 중 하나인 key로 설명할겠습니다. 아래 예시를 봅시다. VDOM 트리의 값이 변경됐습니다. 이제 VDOM 트리와 DOM 트리를 동기화 해야 하는데 어떻게 해야할까요? 최적화를 하지 않으면, 모든 값이 바뀝니다. 하지만 만약 key를 이용한 최적화를 한다면, 숫자 1이 빠지고 숫자 7이 들어갔다고 동기화 할 수 있습니다.

동기화

🙋‍♂️ 최적화 기법으로 React 훅만 있는 게 아니군요?

네, 최적화를 하기 위해서 React 훅인 useMemo, useCallback을 써봤을 것입니다. 하지만 이 방법만 있지도 않고, 최적화의 최우선의 방법도 아닙니다. 컴포넌트 분할만 잘 해도 최적화를 할 수 있습니다.

😄 마무리

JSX와 VDOM에 대해 알아봤습니다. 생각보다 많은 사람들이 JSX와 VDOM에 대해 모르고 React를 쓰는 것 같습니다. 저도 잘 몰랐고요! 다음에는 다양한 최적화 기법에 대해 얘기해보겠습니다 😄

profile
기술을 위한 기술이 되지 않도록!

1개의 댓글

comment-user-thumbnail
2025년 11월 30일

헤일리 글 정말 잘 읽었습니다!

제목만 보고는 “최적화와 JSX가 어떤 관계가 있지?” 궁금해서 들어왔는데, 다음 글에서 이어진다니..!! 얼른 다음 글을 낋여와주세요 ㅎㅎㅋㅋ
별 아무 생각 없이 쓰던 JSX를 VDOM과 연결해서 설명해주신 부분이 정말 좋았어요.
헤일리식 추론답게 계속 궁금한 질문이 나와서 이해하기 쉬웠던 것 같아요 ㅎㅎ 👍

읽다가 궁금한 점이 생겼는데, 헤일리의 의견이 궁금해요!

  1. VDOM 트리를 그릴 때는 모든 컴포넌트를 위에서부터 전체를 다시 그리나요?
    부분적으로 그리는지, 전체를 재생성하는지 궁금해졌어요.

  2. 글에서 “VDOM 트리를 쓰는 이유는 유지보수 때문이다”라고 하셨는데,
    조금 더 구체적으로 풀어보는 것도 좋지 않을까? 하는 생각이 들었습니다!

React는 JSX를 기반으로 선언형 UI를 지원해서,
개발자가 UI의 최종 상태만 선언하면 나머지는 React가 알아서 처리하는데,
만약 선언형 UI가 아니라면 개발자가 직접 DOM을 찾아 수정해야 해서 유지보수가 매우 어려워진다

이런 흐름으로 풀면 더 명확해질 것 같아요!

답글 달기