React 내부 동작원리를 알아보자(2) - Virtual DOM의 동작을 살펴보자

방구석 코딩쟁이·2024년 1월 24일
0

이 시리즈는 "가장 쉬운 웹개발 with Boaz" 님의 [React 까보기 시리즈] 를 기반으로 만들어졌습니다.

Virtual DOM의 동작을 Render Phase와 Commit Phase로 나누어서 살펴볼 예정입니다.

VDOM과 React Lifecycle

VDOM은 프로그래밍 컨셉입니다. 메모리 상에 UI와 관련된 정보를 띄우고, react-dom(renderer)과 같은 라이브러리에 의해 실제 DOM과 sync를 맞춥니다 이 과정을 재조정(reconciliation)이라 부르고 reconciler가 관여합니다.

왜 가상으로 할까요? 실제 DOM으로 구현한다면 mount와 paint 작업이 들어가기 때문에 가상보다 비용이 더 크게 됩니다.

VDOM은 어떻게 구현되어 있을까요? 아래의 그림처럼 Fiber node로 구성된 Tree 형태입니다.

  • 원 하나하나가 Fiber node 입니다.

Tree가 2개가 존재합니다. current 트리와 workInProgress 트리입니다.

  • current

    • DOM에 mount된 fiber 입니다.
    • current 트리의 끝을 보시면 render라는 함수의 인자로 들어가게 되는 것을 보실 수 있습니다.
    const root = React.createRoot(document.getElementById('root') as HTMLElement)

    위의 과정을 거쳐 실제 HTML의 Element를 current 트리의 Root로 만듭니다. 루트를 만든 뒤에는 root.render() API를 통해 current 트리를 만듭니다.

  • workInProgress

    • 이름에서 유추를 해볼 수 있듯이 작업 중인 트리입니다. current 트리에서 자기복제하여 만들어졌으며 alternate로 서로를 참조합니다. fiber는 첫 번째 자식만을 child 속성으로 참조하며 나머지 자식들을 sibling으로 참조합니다. 모든 자식은 부모를 return 속성으로 참조합니다.
      (fiber는 자바스크립트 객체입니다)
    • render phase에서 작업 중인 fiber를 가진 트리입니다.
    • commit phase를 지나면서 workInProgress 트리는 current 트리가 됩니다.
      이과정은 그림을 통해서 쉽게 설명이 가능한데, Root Nodecurrent 속성을 current 트리에서 workInProgress 트리로 변경하면 됩니다. 그리고,current 트리에서 또 자기복제를 통해 새로운 workInProgress트리를 만듭니다.

위 과정에 대한 설명을 들었으면 동일한 트리가 2개를 가지고 있다는 생각이 들 것입니다. 이러한 구조를 더블 버퍼링이라 부릅니다.

왜 더블 버퍼링 구조를 갖게 되었을까요? 직접 작업 중인 workInProgress 트리를 특정한 이유로 다 삭제해야할 때나 유연하게 순서를 조정해야 할 때가 있는데, 그러기 위해서는 원본이 필요하고 원본을 참조해야할 수 있습니다.

컴포넌트 리렌더링은 컴포넌트 호출 후 그 결과가 VDOM에 반영됩니다. DOM에 mount되어 paint되는 것이 아닙니다.

React Lifecycle

render phasecommit phase가 리액트 라이프 사이클 안에 있는 단계입니다.

Render phase

VDOM을 재조정(reconciliation)하는 단계입니다.

  • reconciliation이란 fiber Node로 확장된 객체를 추가, 수정, 삭제하는 것을 말하며, reconciliation(추가, 수정, 삭제 작업)이 일어나기 위해서는 WORK를 scheduler에 등록해야 합니다.
    • WORK(작업): reconciler가 컴포넌트 변경을 DOM에 적용하기 위해 수행하는 작업입니다.
      스케줄러가 등록한 WORK들을 타이밍에 맞게 실행하는 역할을 담당하고 있음
    • react elementfiber Node로 확장시켰다는 의미
  • reconciler가 담당합니다.
    reconciler의 설계를 stack에서 fiber 구조로 바꾸면서 렌더링의 순서를 변경할 수 있게 되었습니다. stack 아키텍처의 경우는 나중에 들어온 것을 우선적으로 처리를 해야했는데, fiber 아키텍처는 들어온 순서대로 처리하지 않아도 되었기 때문입니다. abort, stop, restart 등의 메서드를 호출하면서 멈출 수도, 다시 시작할수도 있게 되었습니다. (즉, useTransition 등의 API를 통해 렌더링 우선순위 변경이 가능합니다.)

Commit Phase

재조정이 끝난 VDOM을 DOM에 적용하고, 라이프사이클을 실행하는 단계입니다.
일관성을 위해 동기적으로 실행을 합니다.
결과적으로 DOM 조작이 다 처리(일괄처리)를 하고, 리액트가 콜스택을 비워준 다음에서야 브라우저가 조작이 끝난 DOM에 대해 Paint를 시작하게 됩니다

profile
풀스택으로 나아가기

0개의 댓글