가상돔과 React 의 관계를 React 랜더링 동작 원리를 통해 알아보자.

WE SEE WHAT WE WANT·2023년 10월 4일
0

React

목록 보기
5/6
post-thumbnail

가상돔과 리액트의 관계를 알아보기에 앞서, 간단하게 개념설명을 진행하겠습니다. 🕶️

돔이란?

" 웹페이지의 구조를 표현하는 객체 모델. HTML/ XML 문서에 접근하기 위한 인터페이스.DOM은 HTML과 스크립팅언어(Javascript)를 서로 이어주는 역할"

가상돔이란?

" 실제 돔(Document Object Model)의 가벼운 복사본. 실제 돔과 동일한 구조를 가지지만, 메모리상에 존재하는 가벼운 복사본!! 직접적으로 dom에 있는 문서에 접근하지 않는다. 변경사항을 하나의 가상 돔에 모았다가 DOM에 보내는 기술"


돔의 구조(돔트리)

트리형태의 구조로 표현됨 (실제 돔의 구조와 유사함) 웹/앱의 UI를 계층적으로 표현.

Node : 실제 돔의 요소를 나타냄. HTML요소, 텍스트, 주석 등 다양한 유형의 노드가있음.
Element : HTML 요소를 나타내는 노드.
같은 HTML 태그로 표현 가능. Element는 태그이름, 속성(Attribute), 자식노드를 포함!
Text: 실제 돔의 텍스트 내용
Attribute: Element는 Attribute를 가질 수 있음. ‘class’, ‘id’, ‘src’ 와 같은 속성을 가진 요소를 표현 가능. Attribute는 Element 의 추가정보를 제공함.
Children: 가상돔의 노드는 다른 노드들을 자식으로 가질 수 있음.


가상돔의 동작원리

1->5에 이어지는 동작원리의 순서를 확인해보자.

  1. 초기 랜더링 : 초기에는 실제 돔과 동일한 구조를 가지고 있음. 초디상태를 기반으로 가상돔이 생성됨.
  2. UI 업데이트 : 웹/앱에서 상태변경이 발생하면, 가상돔은 <변화된 가상돔 vs 이전 가상돔>의 차이를 계산함.
  3. 가상돔 비교 : 요소의 유형, 속성, 텍스트 내용 등을 비교해서 이전가상돔과의 변경된 부분을 식별함.
  4. 돔 조작 : 변경된 부분을 실제 돔에 반영하기 위해 돔 조작 실행.
  5. 실제 돔 업데이트 : 가상돔의 돔 조작 완료 후, 실제 돔은 변경된 부분에 대한 업데이트를 실행 → 이를 통해 UI가 새로운 상태로 업데이트됨.

가상돔과 REACT의 관계

🧐 Virtual DOM 의 대유행을 유발하는 한 라이브러리의 등장… 두둥!!

FaceBook이 React 와 Flux 를 만들게된 계기가 무엇일까?

  • 발단: Facebook에서 메세지가 오지않았는데, 메세지가 와있다고 뜨는 심각한 버그가 있었는데, 실제로 그 버그를 해결하지 못하는 상황이 옴.
  • "Facebook 알림 버그”→ 구체화 된 아이디어 : 전부 다 Virtual DOM 에 새로 그리고, 기존에 비해 변경된 부분만 DOM에 한 번에 보내버리자!!
    → DOM에 변경사항을 조작해서 집어넣지 말고 그냥 데이터가 바뀔 때마다 전부 다 다시 그려 버리면 버그가 생길 일이 없지 않냐는 생각을 하게되고, 아이디어를 구체화함.
  • 결국 React 는 성공했고, React를 이용하면 데이터 흐름과 DOM의 차이에 의한 버그가 발생하지 않았고, 코드를 선언적으로 깔끔하게 작성 할 수 있게 됨.
    (== 데이터 바인딩 or 흐름을 신경 쓸 필요가 없고, 상태에만 집중하여 선언적인 코드를 짬)

React 에서 실제 돔이 아닌 가상돔을 사용하는 이유는?

  • 성능 개선 : 웹/앱에서 상태가 변경될 때마다 실제 돔을 직접 조작하는 것은 비용이 크고 성능에 부담을 줄 수 있음 → 이런 문제를 해결하기 위해 가상돔은 실제 돔과의 차이를 분석 + 최소한의 변경을 적용함으로 불필요한 레이아웃 계산과 리플로우를 방지하고 성능을 개선함.
  • 선언적 UI 업데이트 + 개발 생산성 : 상태의 변화에 따라 UI를 업데이트하기 위해 선언적인 방식을 사용하는데, 가상돔 비교를 통해 변경된 부분만 감지 후 업데이트를 하기에 개발자가 UI 업데이트에 집중할 수 있음!
  • 크로스 플랫폼 개발 : 가상돔을 사용하면 플랫폼에 종속되지 않음! 동일한 코드를 여러 플랫폼에 재사용이 가능. React Native 가 React와 동일한 가상돔을 사용하여 앱을 개발하는 것도 가능!

그래서… REACT가 뭐라고? 요약하면!

  1. React는 Virtual DOM, 라이프사이클 메서드, 단방향 데이터 흐름 등의 특징을 가지고 있음
  2. 사용자와 인터렉션을 통한 UI의 표현을 효율적으로 해주는 것에만 집중
  3. 모두 View쪽을 효율적이고 독립적으로 다루기 위한 목적을 가짐

REACT의 랜더링 동작원리

1. 초기 랜더링 단계

  • 랜더링이란 ?
    - 현재 props 및 상태를 기반으로 React 가 컴포넌트에게 UI 영역이 어떻게 보이길 원하는지 설명을 원하는 프로세스

  • [1단계] 렌더링 큐(Rendering Queue)를 사용하여 컴포넌트의 업데이트를 관리
    - 상태(State) 및 속성(Properties) 변경
    - 컴포넌트 업데이트 계획
    - 랜더링 큐에 업데이트 등록
    - 랜더링 시작
    - 컴포넌트 랜더링
    - 가상돔 비교 및 실제 돔 업데이트
    - 자식 컴포넌트 렌더링

  • [2단계] ReactDOM.render() 메서드를 사용하여 root 컴포넌트를 실제 돔에 마운트

  • [3단계] root 컴포넌트의 render() 메서드 호출 → 해당 컴포넌트 & 하위 컴포넌트들의 가상돔 트리가 생성됨.

2. 가상돔 생성 및 비교 단계

  • 작은 규모의 레이아웃(리플로우)이 여러번 발생하는 것보다 큰 규모의 레이아웃이 한 번 발생하는 것은 성능상의 큰 차이를 나타냄
  • 리액트는 위와 같은 얕은 비교와 일괄 돔 업데이트 방식을 이용해 성능 향상을 이끄는 것!

3. 컴포넌트 라이프사이클 메서드

  • 라이프사이클 메서드를 통해 특정 시점에서 추가적인 작업을 수행할 수 있음.
  • 예시) 컴포넌트가 마운트되거나 업데이트되는 시점에 실행되는 메서드들을 활용하여 데이터 로딩, 이벤트 처리 등의 작업을 수행할 수 있음
  • 그림 설명 (아래)

4. 상태(State) 업데이트

  • 컴포넌트의 상태가 변경되면, 상태 업데이트를 통해 UI를 업데이트 함.
  • 함수형 컴포넌트 : useState 훅을 사용하여 상태를 초기화
  • setState() 메서드 사용 : 변경된 상태를 가상돔과 비교하여 필요한 부분만을 업데이트 & 실제 돔에 반영
  • 주의할점 : 상태 업데이트의 불변성 유지 → 기존 상태를 직접 변경하지 않고, 새로운 상태 객체를 생성하여 업데이트하는 것을 의미! (이를 위해 spread 연산자(...)를 사용)
  • 비동기적 상태 업데이트에 주의

5. 이벤트 처리

  • 사용자의 상호작용에 응답하고 UI를 업데이트하는 핵심적인 부분!!
  • 이벤트 핸들러 함수를 컴포넌트 안에서 정의 → 클래스 컴포넌트 형태로 정의하거나 일반함수로 정의.
  • 가상돔 or 실제 돔에서 발생. 리액트는 이벤트를 컴포넌트로 전달하여 처리함.
  • 자주 사용되는 이벤트 → 클릭(click), 변경(change), 입력(input), 제출(submit)

6. 재귀적 랜더링

  • Recursive Rendering 은 컴포넌트 내부에서 자기 자신을 호출하여 반복적으로 렌더링을 수행하는 것을 일컬음.
  • 주로 컴포넌트 트리의 구조와 데이터에 기반하여 동적으로 UI를 생성하거나 반복적인 패턴을 표현할 때 사용
  • React는 컴포넌트의 계층 구조를 통해 재귀적인 렌더링 실행
  • 컴포넌트의 상태나 속성이 변경되면 해당 컴포넌트와 그 하위 컴포넌트들의 렌더링이 재귀적으로 호출하여 트리를 구성
  • 예) 트리 구조를 가진 댓글 컴포넌트가 있다면, 각 댓글은 자식 댓글을 가질 수 있음. 부모 댓글 컴포넌트가 자식 댓글 컴포넌트를 렌더링할 때, 자식 댓글 컴포넌트는 다시 자신을 호출하여 자식 댓글을 렌더링하게 됨.
  • 주의할점 : 종료조건을 적절하게 사용하여 무한루프에 안빠지게 하자!

REACT의 주요한 규칙

1.가상돔 동등성 비교

  • 가상돔 요소의 타입, 속성, 자식 요소들을 비교하여 동일한지 여부를 판단

2.키(key) 사용

  • 각 컴포넌트는 유일한 키(Key)를 가지고 있어야 함.
  • 키를 통해 해당 컴포넌트의 위치를 식별하고 재조정 함.

3.상태(State)와 속성(Props) 변경

  • 상태나 속성이 변경되면 해당 컴포넌트와 하위 컴포넌트들의 렌더링이 트리거됨.
  • 변경된 컴포넌트들을 업데이트 큐에 등록하고, 이후 업데이트 작업을 수행

4.최적화

  • 변경 사항이 없는 컴포넌트들을 스킵하여 성능을 향상시킴
  • 메모이제이션(Memoization)과 같은 최적화 기법을 활용하여 중복 계산을 피하고, 필요한 변경 사항만을 처리

가상돔 + React 를 사용함으로 인한 단점은 없을까?

- 복잡성

virtual DOM 데이터와 diff 알고리즘으로 reconciliation 과정을 거쳐 화면을 수정 → 이 과정은 n개의 node가 있는 트리에 대해 O(n) 복잡도를 가지게 됨.

- 초기 로딩 속도

복제본이기 때문에 추가적인 작업 및 계산이 필요하기 때문에 실제 돔보다 초기 랜더링 속도가 느릴 수 있음.

- 메모리 사용량

컴포넌트가 복제되고 이전 상태와 비교되는 과정에서 추가적인 메모리가 필요. 하지만 일반적으로 크게 문제 x

- 성능저하

가상돔은 모든 컴포넌트의 변화를 추적하고 이에 대한 업데이트를 수행하기 때문에 불필요한 랜더링이 발생 할 수 있음.

=> 이를 최적화하기 위해 리액트에서 제공하는 기능(React.memo 와 같은) 을 활용하여 컴포넌트 업데이트를 제어하고 성능을 개선해야 함.


(추가) Block Virtual DOM ?

: 가상돔을 블록 단위로 처리하는 방식! 컴포넌트의 랜더링을 블록으로 나누고, 각 블록은 독립적으로 처리되며 업데이트가 됨. (컴포넌트, 요소 포함)

장점

  • 성능향상 : 변경 사항이 있는 블록만 업데이트 시킴.
  • 모듈성 강화 : 각 블록은 독립적인 기능! 컴포넌트의 모듈성을 강화하고 유지 보수성을 향상
  • 효율적인 리랜더링 : 불필요한 리렌더링 없이 컴포넌트의 업데이트 과정을 최적화 + 반응성을 향상
  • 라이브러리 : Million.js
    https://pyjun01.github.io/v/million-js/

부록 : 잘못알고있는 소소한 지식

  • 리액트가 DOM 보다 빠르다 ? 답변은 아래 사진을 참고해보자.


참고 링크

https://developer.mozilla.org/ko/docs/Web/API/Document_Object_Model/Introduction
https://gist.github.com/sebmarkbage/75f0838967cd003cd7f9ab938eb1958f
https://velog.io/@huurray/React의-탄생과-Flux-패턴에-대하여
https://velopert.com/3236
https://velog.io/@woohm402/virtual-dom-and-react
https://ko.legacy.reactjs.org/docs/reconciliation.html
https://million.dev/blog/virtual-dom

profile
프론트엔드 주니어입니다. 그런데 서비스 기획을 곁들인,,,

0개의 댓글