2.1 - 2.2: JSX와 DOM

gonn-i·2025년 3월 18일
post-thumbnail

2.1 JSX란?

  • JSX는 ECMAScript 라 불리는, 자바스크립트의 표준은 아니다.
  • 목적으로는, 다양한 속성을 가진 트리 구조를 토큰화해서 ECMASCipt로 변환하는데에 초점을 둔다. (단, 트랜스파일 구조를 거쳐)

JSX란, 요약하자면 JS 내부에서 표현하기 까다로웠던 XML 스타일 트리 구문을 작성하는데 도움을 주는 문법이다.


2.1.1 JSX 정의

JSX는 4가지 컴포넌트를 기반으로 구성되어 있다.
(JSXElement / JSXAttributes / JSXChildren / JSXStrings)

  • JSXElement : HTML 의 요소와 비슷한 역할을 한다. 형태는 아래 4가지와 같다.
    • JSXOpeningElement: 선언 시작을 의미, 말그대로 오프닝을 담당
    • JSXClosingElement: JSXOpeningElement 가 종료됐음을 알리는 요소
    • JSXSelfClosingElement : 요소가 시작되고, 스스로 종료되는 형태를 의미
    • JSXFragment : 아무런 요소가 없는 형태, <></>
  • JSXElementName : JSXElement의 요소이름으로 쓸 수 있는 것을 의미
    • JSXIdentifier : JSX 내부에서 사용할 수 있는 식별자, $와 _로 시작할 수 있지만, 숫자로 시작하는 것은 불가능
    • JSXNamespacedName : :을 사용하여 네임스페이스를 구분할 수 있다, 단, 한번만 사용 가능
    • JSXMemberExpression : .을 사용하여 요소를 연결할 수 있다, 단, 여러 개의 .을 사용할 수 있지만, :과 함께 사용할 수는 없다
  • JSXAttributes: JSXElement에 부여할 수 있는 속성을 의미, 필수값은 아니다.
    • JSXSpreadAttributes : 전개 연산자 (...)를 이용해 속성을 전달할 수 있다.
    • JSXAttribute : 속성은 키-값 형태로 표현 (JSXAttributeName (key) / JSXAttributeValue (속성의 값) )
  • JSXChildren : JSXElement의 자식 값을 나타낸다. 기본 단위는 JSXChild로 JSXChildren은 0개 이상의 JSXChild를 포함할 수 있다.
    • 내부에는 일반적인 문자열 텍스트, 다른 JSX 요소, <>...</>, {}로 감싼 표현식을 사용할 수 있다.
  • JSXStrings : HTML과 JSX 간 복사 & 붙여넣기를 쉽게 하기 위해 설계된 문자열 표현 방식
    • 큰따옴표(")로 구성된 문자열 / 작은따옴표(')로 구성된 문자열 / JSXText (특수 문자 {, <, >, } 제외) 가 여기에 속한다
    • 단, HTML 과의 차이점은 JavaScript에서는\가 이스케이프 문자로 사용되므로, 문자 그대로 표현하려면 \\로 이스케이프해야 한다.

2.1.2 JSX는 자바스크립트에서 어떻게 변환될까

@babel/plugin-transform-react-jsx 플러그인을 통해, JSX 구문을 자바스크립트가 이해할 수 있는 형태로 변환한다.


2.2 가상 DOM과 리액트 파이버

2.2.1 DOM과 브라우저 랜더링 과정

DOM이란? (-> 웹페이지에 대한 인터페이스)
웹페이지의 콘텐츠와 구조를 어떻게 보여줄지에 대한 정보이다.

📍 브라우저 랜더링 과정 (a.k.a Critical Rendering Path)

1️⃣ HTML 다운로드 및 파싱 → DOM 트리 생성

2️⃣ CSS 다운로드 및 파싱 → CSSOM 트리 생성
(브라우저는 , display: none 과 같이 사용자에게 보여지지 않는 부분은 방문해 작업하지 않는다. 트리 분석을 빠르게 하기 위해서)

3️⃣ Render Tree 생성 → 화면에 보이는 요소만 포함

4️⃣ 레이아웃(Layout, Reflow) → 요소의 위치와 크기 계산

5️⃣ 페인팅 → 요소에 색상, 이미지 등 시각적 스타일 적용
(이때, 레이아웃 과정을 거치면, 페인팅도 거치게 된다.)

2.2.2 가상 DOM의 탄생과정

브라우저에 웹 페이지를 랜더링하는 것은 비용이 든다.
초기 랜더링 이외에도, 사용자 인터렉션에 따라 변경되는 사항도 고려해야 한다.

특히, 위치나 크기를 다시 계산해야 하는 경우
-> 레이아웃 + 리페인팅 을 야기하기 때문에 리소스적으로 비용이 든다.
또한, DOM 변경을 일으키는 요소가 많은 자식을 가질 경우, 하위 자식들도 덩달아 변경돼야 하기에 이에 대한 고려가 필요하다.

그래서 등장한 것이 바로, 가상 DOM이다. (이하 VDOM)

VDOM
실제 브라우저의 DOM이 아닌 리액트가 관리하는 가상의 DOM을 의미한다.
브라우저가 아닌 메모리에서 계산하는 과정을 거치면(VDOM 을 사용하면),
실제 여러번 발생했을 랜더링 과정을 최소화할 수 있다.

오해 ) 일반적인 DOM을 관리하는 브라우저보다, VDOM이 항상 빠를까?
-> 무조건 빠른 것이 아니라 리액트의 이 가상 DOM 방식은 대부분의 상황에서 웬만한 애플리케이션을 만들 수 있을 정도로 충분히 빠르다는 것이다.
(가상 DOM으로 랜더링 과정을 모아서 최적화시키는 건 맞지만, 항상 빠르다고 볼 순 없다. )


2.2.3 가상 DOM을 위한 아키텍처, 리액트 파이버

리액트 파이버란?

  • 파이버 재조정자가 관리하는, 자바스크립트 객체
  • DOM과 - VDOM 비교를 통해 변경사항을 수집하며, 차이 정보를 가지고 있는 파이버를 기준으로 화면에 랜더링을 요청하는 역할을 한다.

파이버가 하는 일

  • 작업을 작은 단위로 분할하고 쪼갠 다음, 우선순위를 매긴다.
  • 이러한 작업을 일시 중지하고, 나중에 시작할 수 있다.
  • 이전에 했던 작업을 다시 재사용하거나, 필요하지 않는 경우 폐기할 수 있다.

초기 리액트 알고리즘은 스택 알고리즘 ==> 모든 과정이 동기적으로 이루어졌다.
비효율적인 스택 구조를 타파하고자, 파이버 개념이 생겼다.

파이버의 작동과정

  • 렌더 단계
    리액트는 가상 DOM을 기반으로 변경 사항을 계산 (= 사용자에게 노출되지 않는 모든 비동기 작업을 수행)
    이 과정에서 우선순위에 따라 작업을 중지하거나 버리는 등의 작업을 한다.
  • 커밋 단계
    변경 사항을 실제 DOM에 반영하는 과정. 이 단계는 동기적으로 실행되며, 중단될 수 없다
    React는 commitWork()를 실행하여 실제 DOM을 업데이트하고, useEffect 같은 side effect들을 처리함.

리액트 요소와 유사하지만, 큰 차이점은
리액트 요소는 랜더링이 발생할때마다 새롭게 생성되지만, 파이버는 가급적이면 재사용된다.

파이버는 하나의 element에 하나가 생성되는 1:1 관계를 가지고 있다. (여기에서 요소는 리액트 컴포넌트나, HTML DOM 노드 등을 말한다.) 생성된 파이버는 state가 변경되거나, 생명주기 메서드가 실행되거나 DOM 변경이 필요한 시점에 실행된다.

리액트의 핵심 원칙은 UI를 문자열, 숫자, 배열과 같은 값으로 관리한다. (파이버의 객체 값에서도 알 수 있다.)
변수에 따라 이러한 UI 값을 보관하고, 리액트의 자바스크립트 코드 흐름에 따라 이를 관리하고, 표현하는 것이 바로 리액트이다.

파이버 트리

리액트 내부에는 현재 모습을 담은 파이버 트리와,
작업 중인 상태를 나타내는 workInProgress 트리가 있다.

리액트 파이버 작업이 끝나면, 리액트는 단순히 포인터만 변경해서 workInProgress 트리를 -> 현재 트리로 바꿔버리는데,
이 기술을 더블 버퍼링이라고 한다.

Fiber 트리 탐색 과정

  • beginWork() 실행

    	각 Fiber 노드를 트리 형식으로 순회하면서 작업을 수행함.
    	더 이상 자식이 없는 노드(리프 노드)를 만날 때까지 탐색함.
    	completeWork() 실행
  • completeWork() 실행

    	자식 노드의 처리가 끝나면, 현재 노드의 작업을 완료함.
  • 형제가 있다면 형제 노드로 이동

    	`현재 노드가 형제 노드를 가지고 있다면, 형제 노드의 beginWork()를 실행함.
  • 더 이상 형제 노드가 없으면 부모로 돌아감 (return)

    	형제 노드도 모두 처리되었다면, 부모 노드로 돌아가 자신의 작업이 완료되었음을 알림.
  • 이렇게 생성된 트리에서, setState로 업데이트가 발생하면 기존(current) 트리를 기반으로 새로운(workInProgress) 트리를 생성한다.
  • 이때, 기존 Fiber를 재사용하며, 필요한 부분만 업데이트하여 리소스를 절약.
  • 예전에는 동기식으로 처리했지만, 이제는 우선순위에 따라 중단/재개/폐기 처리한다.
  • 작업 단위를 나누어 애니메이션·입력은 우선순위 높게, 목록 렌더링은 낮게 설정하며 최적의 순위로 작업을 완료하게끔 작동한다.

2.2.4 파이버와 가상 DOM

  • Fiber는 React 컴포넌트 정보를 1:1로 가지며, 비동기적으로 처리된다.
  • 실제 DOM 업데이트는 동기적으로 이루어져야 하므로, 가상 DOM에서 미리 연산 후 적용하는 것이 효율적이다.
  • 가상 DOM은 웹에서만 통용되는 개념인데, Fiber는 React Native에서도 사용 가능하다.
  • 즉, Fiber와 가상 DOM은 동일한 개념이 아니다, React의 렌더러에 따라 다르게 작하더라도 내부적으로 파이버를 통해 조정되는 과정은 동일하기 떄문에 동일한 재조정자를 사용할 수 있게 된다!

정리!! 📌 Fiber와 가상 DOM의 관계
가상 DOM : 실제 DOM을 직접 조작하지 않고, 메모리상에서 변경 사항을 계산한 후 효율적으로 업데이트하는 DOM
Fiber : 가상 DOM을 보다 최적화하여 조작하기 위한 React 내부의 데이터 구조이자 알고리즘.

2.2.4 정리

가상 DOM과 리액트의 핵심은 브라우저의 DOM을 더욱 빠르게 그리고 반영하는 것이 아니라 바로 값으로 UI를 표현하는 것이다. 화면에 표시되는 이를 자바스크립트의 문자열, 배열 등과 마찬가지로 값으로 관리하고 이러한 흐름을 효율적으로 관리하기 위한 메커니즘이 바로 리액트의 핵심이다.

profile
https://gonnn-i.tistory.com/

0개의 댓글