본문 바로가기
React

JSX와 React Virtual DOM

by jewook3617 2020. 12. 6.

지난번 글에서  JSX가 HTML로 보이지만 사실은 javascript 코드라고 했습니다. 그리고 ReactDOM.render 함수가 첫 번째 파라미터로 넘어온 JSX를 HTML로 바꾸어 두 번째로 넘어온 HTML element에 넣어준다고 했습니다.

그럼 JSX가 왜 HTML이 아닌 javascript인지 살펴보겠습니다.

JSX

먼저, 다음과 같은 JSX 코드가 있습니다.

<div id="jsx">
  <h1>What is JSX</h1>
  <p>JSX is ...</p>
</div>
	

React는 Babel이라는 도구를 통해 JSX를 다음과 같이 바꿔줍니다. 원래는 Babel 설정을 따로 해줘야 하지만 create-react-app으로 React 프로젝트를 만들면 Babel 설정을 할 따로 할 필요없이 그냥 사용할 수 있습니다. 여기에 가면 온라인으로 바벨을 사용해 볼 수 있습니다.

React.createElement(
  "div",
  { id: "jsx" },
  React.createElement("h1", null, "What is JSX"), 
  React.createElement("p", null, "JSX is ...")
);

이렇게 보니 JSX가 javascript 코드라는 말이 이해가 잘 되시나요? 

HTML처럼 생긴 태그 형태의 JSX를 React.createElement 함수를 통해 React가 해석할 수 있는 element로 바꿔줍니다. HTML은 계층구조이기 때문에 React.createElement로 생성된 element도 마찬가지로 계층구조를 가지게 됩니다.

React.createElement 함수의 파라미터는 다음과 같습니다.

React.createElement(
  type,
  properties,
  children
)

첫 번째로 element의 type을 받습니다. type은 HTML 태그가 될 수도 있고 Component라고 불리는 사용자가 직접 만든 태그가 될 수도 있습니다.

두 번째는 element의 property를 javascript object 형태로 받습니다. 

세 번째부터는 element의 하위 element들입니다. 하위 element는 여러개가 있을 수 있으므로 세 번째부터 그 이후로 들어오는 파라미터는 모두 element의 children으로 간주합니다. 하위 element가 텍스트라면 그 텍스트가 그대로 파라미터로 넘어갑니다.

그럼 아래 코드가 실행이 될 때 어떤 일이 생기는지 알아보겠습니다.

ReactDOM.render(
  <div id="jsx">
    <h1>What is JSX</h1>
    <p>JSX is ...</p>
  </div>,
  document.getElementById("root")
);

ReactDOM.render 함수가 실행될 때 Babel이 JSX를 React.createElement로 변환해줍니다. 그리고 React.createElement 함수가 React element들을 생성합니다. 즉, 아래와 같은 형태로 바뀌는 것입니다.

ReactDOM.render(
  React.createElement(
    "div",
    { id: "jsx" },
    React.createElement("h1", null, "What is JSX"),
    React.createElement("p", null, "JSX is ...")
  ),
  document.getElementById("root")
);

위 두 코드의 결과는 같습니다. React.createElement를 직접 사용하면 element 구조가 복잡해질수록 사용하기 불편하기 때문에 JSX를 사용하는 것입니다. JSX는 단지 React.createElement의 단축문법일 뿐입니다.

ReactDOM.render 함수는 React.createElement 함수를 통해 생성된 React element들을 HTML로 바꾸어 id가 root인 HTML element의 하위 element로 넣어줍니다.

Virtual DOM

React element가 생성되면 그것이 바로 실제 DOM으로 바뀌는 것이 아니라 React에서 내부적으로 element들을 저장해놓습니다. 그것을 Virtual DOM(VDOM)이라고 부릅니다. Virtual이라는 이름이 붙어서 의미가 와 닿지 않을 수 있는데 Virtual DOM은 React 자체적으로 가지고 있는 실제 DOM의 복사본이라고 생각하시면 됩니다. Virtual DOM은 React element로 이루어져 있고 실제 DOM은 HTML로 이루어져 있다는 점은 다르지만 담고 있는 내용은 동일합니다.

ReactDOM.render 함수는 Virtual DOM에 저장되어 있는 element 들을 실제 DOM에 반영해주는 역할을 합니다.

하지만 javascript에서는 document 객체를 통해 실제 DOM에 바로 접근할 수 있기 때문에 굳이 Virtual DOM을 거치지 않더라도 React element를 실제 DOM에 반영할 수 있습니다. 그렇다면 왜 element를 바로 실제 DOM에 반영하지 않고 Virtual DOM을 한번 거치는 것일까요?  그 이유는 DOM 조작의 효율성 때문입니다.

SPA는 한 번의 request로 모든 페이지의 정보를 다 가져옵니다. 따라서 페이지의 내용이 전부 바뀌더라도 그것은 javascript에 의해 DOM의 내용이 전부 수정된 것이지 server에서 새로 가져온 내용들이 아닙니다. 그렇기 때문에 SPA에서 javascript를 통한 DOM 조작이 매우 빈번하게 일어납니다. DOM 조작은 비용이 매우 큰 연산이기 때문에 효율적이지 못한 DOM 조작이 많이 발생한다면 performance에 큰 영향을 끼칠 수 있습니다.

다음은 React 공식 홈페이지에서 제공하는 예제 코드입니다.

function tick() {
  const element = (
    <div>
      <h1>Hello, world!</h1>
      <h2>It is {new Date().toLocaleTimeString()}.</h2>
    </div>
  );
  ReactDOM.render(element, document.getElementById('root'));
}

setInterval(tick, 1000);

tick 함수는 현재 시간을 보여주는 element를 만들고 ReactDOM.render 함수를 실행합니다. 그리고 setInterval 함수를 통해 tick 함수가 1초에 한 번씩 호출되도록 합니다. 

이 코드를 실행하면 1초에 한 번씩 {new Date().toLocaleTimeString()} 부분이 현재 시간으로 업데이트됩니다. 

여기서 개발자 도구를 열어보면 재미있는 사실을 확인할 수 있습니다. 다음 gif도 React 공식 홈페이지에서 제공하는 gif입니다.

분명 tick 함수가 1초에 한 번씩 호출되면서 element 전체가 새로 생성되는데 실제 DOM에서는 이전 화면과 달라지는 {new Date().toLocaleTimeString()} 부분만 새로 렌더링 되고 있습니다. 이것이 바로 Virtual DOM의 존재 이유입니다.

ReactDOM.render 함수가 실행이 될 때마다 React는 Virtual DOM을 새로 만듭니다. 그리고 ReactDOM.render 함수가 실행되면서 새로 만들어진 VIrtual DOM과 실제 DOM의 내용을 비교해 달라진 부분을 찾아냅니다. 그리고 새로운 VIrtual DOM 전체가 아닌 찾아낸 달라진 부분만 실제 DOM에 반영해줍니다.

Virtual DOM은 브라우저 화면에 표시되는 것이 아니라 내용이 메모리에 저장만 되고 있기 때문에 Virtual DOM을 새로 만드는 것은 비용이 큰 연산이 아닙니다. 하지만 Virtual DOM을 새로 만들고 실제 DOM과 달라진 부분을 찾아냄으로써 비용이 큰 실제 DOM 조작을 줄일 수 있습니다.

React를 사용하지 않고 javascript로 실제 DOM을 바꾸려면 document 객체의 createElement(), appendChild() 등의 함수들을 통해서 일일이 코드 작성을 해줘야 했지만 React를 사용하면 DOM 조작은 Virtual DOM, ReactDOM.render 함수에게 맡기고 어떤 데이터를 어떤 형태로 화면에 보여줄 것인지만 신경 쓰면 됩니다.

JSX의 정체가 무엇인지, React는 JSX를 어떤 과정을 통해 브라우저 화면에 렌더링 하는지에 대해 알고 있으면 React 프로그래밍을 하는데에 도움이 많이 된다고 생각합니다.

'React' 카테고리의 다른 글

VSCode에 React + ESLint + Prettier 설정하기  (0) 2021.11.01
React 시작하기  (0) 2020.08.08
React는 무엇이고 왜 사용하는가?  (0) 2020.06.28