리액트 동작 원리에 대해서 알아보자

write less, do more 이라는 모토를 달고 출시한 jQuery는 동적으로 DOM을 제어한다는 측면에 있어 기본 vanila javascript보다 직관적이고 이해하기 쉬운 코드를 작성할 수 있기 때문에 보다 빠르게 배울 수 있고, 보다 적은 양의 코드로도 개발할 수 있어 많은 사랑을 받게 된다.

// vanila javascript
const h1 = document.querySelectorAll('h1');
h1.forEach((element) => element.style.color = 'green');

// jQuery
$('h1').css('color', 'green');

만약 h1 태그로 감싸진 컨텐츠의 색깔을 초록색으로 바꾸고 싶다면, vanila javascript에서는 querySelector를 이용해 h1 태그를 가진 요소들에 접근하고, 각 요소들의 CSS 스타일을 하나하나씩 변경해 주어야 한다. 반면 jQuery를 이용하면 $ 를 통해 h1 태그를 선택하고, 그 프로퍼티 중 CSS 에 접근하여 색을 변경할 수 있다.

Virtual DOM의 등장

그러나 규모가 큰 웹 어플리케이션이 나오면서 jQuery는 한계를 맞이하게 된다. 물론 쉽게 개발하는 것도 중요하지만, 사용자와의 interaction이 많은 웹 앱 특성상 성능이 가장 중요하기 때문이다.

  1. jQuery는 vanila에 비해 로드 해야하는 패키지가 많아 간단한 코드를 작성하더라도 성능적으로 떨어진다.
  2. jQuery를 이용하면 모듈화나 컴포넌트화에 어렵다.
  3. 사용자가 동적으로 DOM 조작을 할 때 jQuery를 사용하면 배치와 화면표시에 많은 연산을 발생시키기 때문에 브라우저의 성능이 낮아진다.

DOM을 직접 조작하는 것은 안정성이 떨어질 뿐만 아니라 DOM API가 너무 low level 이다. 따라서 DOM을 직접 조작하다 보면 코드의 복잡도가 높아질 수 밖에 없다. 이러한 이유로 인해 Virtual DOM이라는 개념이 등장하게 된다.

그렇다면 Virtual DOM이란 무엇일까?

다음과 같은 예시를 생각해보자 만약 여러분이 웹 어플리케이션을 사용하는 사용자의 요청으로 인해 30개의 노드에 변화를 주어야 한다고 생각해보자.

  1. 변경된 HTML을 바탕으로 DOM tree를 다시 생성한다.
  2. 변경된 CSS를 바탕으로 CSSOM tree를 다시 생성한다.
  3. DOM tree와 CSSOM tree를 결합하여 Render tree를 재생성한다.
  4. Render tree의 각 노드를 화면의 실제 픽셀로 변환하여 페인팅한다.

Virtual DOM을 사용하지 않는다면 1 ~ 4의 과정이 30번 동안 반복될 것이다. 즉, 직접적인 DOM을 조작하기 위해서는 브라우저가 많은 연산을 해야하고, 따라서 브라우저의 성능이 낮아진다는 것이다.

Virtual DOM은 이러한 성능 저하를 막아준다. 만약 뷰에 변화가 발생하더라도, 그 변화는 실제 DOM에 적용되기 전에 가상의 DOM에 먼저 적용시키고 그 최종적인 결과를 실제 DOM으로 한꺼번에 전달해 준다. 이로써 브라우저 내에서 발생하는 연산의 양을 줄이며 성능을 개선시키는 것이다.

리액트의 동작 방식

이러한 Virtual DOM을 사용하는 React가 등장하게 된다. React는 상태 state 나 속성 props 값이 변하게 되면 리렌더링이라는 과정을 통해 화면에 출력된 값을 갱신한다. (리렌더링은 말 그대로, 바뀐 상태나 속성 값을 이용해 화면을 다시 그린다는 뜻이다.)

React은 다음 네 가지의 경우에 리렌더링이 발생한다.

  1. props가 변경되었을 때
  2. state가 변경되었을 때
  3. forceUpdate( )를 실행하였을 때
  4. 부모 컴포넌트가 렌더링 되었을 때

React는 바뀐 상태나 속성 값을 갱신할 때 Virtual DOM을 이용하기 때문에, 빠른 속도로 화면을 변화시킬 수 있다.

다음의 예시를 확인해 보자.

import React, { useState } from "react";

const Hello = () => {
    const [name, setName] = useState('foo');
    return (
        <div> Hello {name} </div>
    );
}

// state가 변경되었을 때
ReactDOM.render(<Hello name="bar"/>, mountNode);

위의 코드에서 name state의 값을 foo 에서 bar 로 바꾼다면, 화면에서도 Hello foo 가 아니라 Hello bar 가 출력되도록 변경되어야 한다. name 은 state이므로 React는 변경을 감지하고 Virtual DOM을 새로 그린 다음 기존 DOM과 비교하여 바뀐 부분만 update한다.

댓글남기기