[React] JSX to Virtual DOM to Real DOM

yongkini ·2022년 3월 9일
0

React

목록 보기
2/19

JSX는 어떻게 Real DOM으로 변환될까

  • 그전에 JSX는 왜쓰는가? : 리액트 공식문서에 따르면 사실 jsx는 리액트를 쓰기 위한 필수템(?)이 아니다. 하지만, 프론트엔드 개발자에게 가장 친숙한 언어인 HTML(마크업 언어)과 닮은 interface를 제공함으로써 개발의 편의를 높이고, 선언형 프로그래밍을 가능케 해준다는 점(jsx 문법 대신 createElement, setAttribute 등을 통해서 element를 절차적으로 생성하는 것과 달리) 에서 JSX는 프론트엔드 개발자에게 굉장히 유용하고, 혁신적인 도구라고 할 수 있다(굳이 쓰지 않을 이유가 없다).
  • React.createElement라는 React 내부의 자체 메서드를 통해서 먼저, JS객체로 변환된다.
const element = (
  <h1 className="greeting">
    Hello, world!
  </h1>
);

위의 코드를 개발자가 코딩하게되면

const element = React.createElement(
  'h1',
  {className: 'greeting'},
  'Hello, world!'
);

WebPack의 플러그인인 Babel이 'React.createElement()'를 호출해서 컴파일 한다.

const element = {
  type: 'h1',
  props: {
    className: 'greeting',
    children: 'Hello, world!'
  }
};

그리고 결과적으로 위에 처럼 React Element로 만들어진다(JS객체).
** react element란? : 화면에서 보고 싶은 것을 나타내는 표현

우리가(개발자) JSX 를 쓰면서 Real DOM으로 변환(document.createElement) 과정을 굳이 해주지 않아도 되는 이유는 위에처럼 자동으로 변환해주는 로직이 react내에 있기 때문이다. 최종적으로 위의 element를 가지고 리액트 내부에서 실제 DOM을 만들게 된다.

React가 DOM을 리렌더링할 때, 변한 부분만 리렌더링한다

: 너무나도 잘알고 있고, 당연하다고 생각해왔던 이 사실에 대해서 다시 생각해보자.

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);

위의 코드를 실행하게 되면, ReactDOM.render() 로직을 통해 id가 'root'인 div 태그의 child로

  <div>
      <h1>Hello, world!</h1>
      <h2>It is {new Date().toLocaleTimeString()}.</h2>
  </div>

위의 jsx를 파싱해서 실제 dom으로 append 하게 된다 그것도 매초(setInterval이니까). 이 때, render 메서드를 매초마다 호출을 하기 때문에 계속해서 해당 부분 전체를 다시 그린다고 생각할 수 있다. 그러나, 여기서 'React DOM' 혹은 Virtual DOM으로 불리는 가상 dom이 자체적인 휴리스틱 알고리즘으로 이전 virtual dom(virtual dom은 두개)과 새로 만들어진 virtual dom 를 상대적으로 빠르게 비교해서 둘 사이에 차이가 생긴 부분만 다시 그리도록 한다. 최종적으로 dom api로 해당 부분만 업데이트를 하는 것이다(차이가 생긴 부분만). 그래서 이 부분을 개발자도구로 실제로 보면 전체가 리렌더링되는 것이 아니라 변화하는 부분만 리렌더링이 되고 있음을 알 수 있다.
: 결론적으로 모두가(개발자들) 알다시피 'ReactDOM.render()'은 index.js에서 '단 한번' ** 리액트 공식문서 내용 발췌

호출하게 된다. 이를 통해 생각해보면, state 변경 등의 리렌더링 이슈가 생길 때마다 ReactDOM.render()가 activate 되고, 위에서처럼 휴리스틱 알고리즘으로 js 객체(virtual DOM) 두개를 비교하고, 차이가 있는 부분에 대해서만 dom api를 통해 실제로 리렌더링을 진행하게 되는 것으로 이해해볼 수 있다. 오늘의 메인 키워드 3개를 이용해 다시 설명해보면, 리렌더링 이슈가 생길 때마다 JSX를 VirtualDOM으로 변환하고(with babel) 그러한 Virtual DOM을 가지고, 이전에 갖고 있던 VirtualDOM(비교용)과 비교를 해서 다른 부분에 대해서만 Real DOM에 실제로 변화를 적용시키는 것으로 리렌더링 과정을 디테일하게 설명해볼 수 있다. 그래서 리액트에서 리렌더링 최적화 작업이 필수적인 것이다. 리액트 자체가 DOM API 사용에 대한 최소화 혹은 추상화를 위해 만든건데, 이러한 최적화가 안돼있다면 만든 이유와 모순을 일으키기 때문이다. 예를 들어, 컴포넌트를 분할하지 않고, 통째로 만들었다고 해보자(하나의 페이지를). 그러면 하나의 state가 변경되면 전체 페이지를 리렌더링하게 된다. 그말은 React가 내부 로직으로 virtualDOM과 VirtualDOM을 비교했을 때 결국 전체가 바뀐다고 판단을 내리게 된다는 말이고, 이와 동시에 브라우저는 전체를 리렌더링(리플로우, 리페인트)하게 되어 리소스 사용이 그만큼 더욱 많아진다는 얘기로 이어지므로 비효율적인 양상으로 판단할 수 있다.

레퍼런스

profile
완벽함 보다는 최선의 결과를 위해 끊임없이 노력하는 개발자

0개의 댓글