본문 바로가기

FrontEnd/React

[React] 리액트 동작 원리

가상 DOM 이해하기

 리액트 프레임워크의 기본 3요소는 가상DOM(Virtual DOM), JSX(JavaScript XML)구문, 컴포넌트(Component)이다.

 react와 react-dom 패키지

  react패키지는 컴포넌트, JXS, 리액트 훅 등 랜더러에 무관한 기능을 공통으로 사용하는 기능들을 제공하는 패키지이다.

 반면 react-dom/client, react-dom/server, react-native 등의 랜더러(renderer) 패키지는 앱이 동작하는 환경(플랫폼)에 종속적인 기능을 제공하는 데 특화된 패키지이다.

 

CSR(client-side rendering) : react, react-dom/client 패키지조합
SSR(server-side rendering) : react, react-dom/server 패키지 조합

모바일 앱(안드로이드, IOS) : react, react-native 패키지조합

또한 react와 렌더러 패키지의 경계에는 가상 DOM이라는 매커니즘이 있다.
가상DOM은 실제 DOM이 아닌 JavaScript를 통해 dom을 추상화 시킨 객체이다.

 

 XML 마크업 언어

  <Person name="Jack" age="32" />는 XML(extensible markup language) 문서 규약을 적용해 작성한 예이다.

 웹 분야에서의 문서(document)는 마크업 언어로 작성한 텍스트가 담긴 파일, 인터넷 망을 통해 전송되는 스트림(stream)을 의미한다. 즉, 문서규약을 따르는 XML이나 HTML 문자열이 담긴 파일이나 스트림은 문서라고 하지 않는다.  그리고 XML이나 HTML 안에는 문서를 구성하는 각각의 요소가 존재한다 (ex) HTML은 html, head, meta, body, div 등)

 문서 객체 모델이란?

  웹 브라우저는 HTML형식의 문자열을 화면에 출력할 때 문자열을 분석(parsing)하여 자바스크립트 객체 조합으로 변경한다.  이는 자신의 특징에 맞춰 인터페이스를 구현하며 모든 객체를 총칭해 문서 객체 모델(document object model, DOM)라고 부른다.
  웹 브라우저의 자바스크립트 엔진은 window라는 이름의 전역변수를 기본으로 제공한다.  window는 웹 브라우저의 특정 웹페이지를 의미하며 Window 타입 객체로서 Window타입을 브라우저 객체 모델(browser object model, BOM)이라한다.

  • document 객체 
    - 웹 페이지 그 자체를 의미한다.  웹 페이지에 존재하는 HTML에 접근하고자 할땐 반드시 document객체부터 접근해야 한다.  window.document(window는 생략가능)
  • document.head, docuemnt.body 객체
    - html 요소는 head, body는 1개씩만 가질 수 있다.
  • document.createElement 메서드
    - 웹 브라우저가 DOM의 다양한 인터페이스를 목적에 맞게 구현한 객체로 생성하기 위해 docuemnt.createElement 메서드를 제공한다. 
    - div요소를 자바스크립트로 생성하는 예시  → let newDiv = document.createElement('div')
  • HTMLElement 인터페이스
    - HTMLElement는 모든 종류의 HTML요소가 구현하는 인터페이스이다.  이 인터페이스를 직접 구현하기도 하지만, 상HTMLElement를 상속받아 자신만의 인터페이스를 구현한다.
    - HTML요소명Element의 형태의 규칙을 갖는다.  앞서 newDiv의 객체 타입은 HTMLDivElement이다.
  • HTMLElement의 부모요소 상속 구조
    -  EventTarget ← Node ← Element ← HTMLElement : HTMLElement는 부모인터페이스 3개를 상속한다.
    - Node는 appendChild 메서드를 제공한다.  HTMLElement는 모든 HTML태그의 부모 인터페이스이다.  즉 모든 HTML태그는 appendChild 메서드를 사용할 수 있다.
    let p = document.createElement("p")  // p 요소 생성
    // p요소를 <body>의 마지막 자식요소로 추가한다.
    document.body.appendChild("p")       // 렌더링

 자바 스크립트만 사용하는 프런트엔드 개발(물리 DOM)

  리액트와 상관없는 일반적인 자바스크립트만을 사용한 프런트엔드 개발이다.   이 부분을 리액로 변경해보자.

import React from 'react'

let pPhysicalDOM = document.createElement('p') // 물리 DOM객체
pPhysicalDOM.innerText = 'Hello physical DOM world!'
document.body.appendChild(pPhysicalDOM)

 리액트를 사용하는 프런트엔드 개발(가상DOM)

    function createElement<P extends {}>(
        type: FunctionComponent<P> | ComponentClass<P> | string,
        props?: Attributes & P | null,
        ...children: ReactNode[]
    ): ReactElement<P>;

 

  document.createElement와 유사하게 react 패키지는 react.createElement라는 함수를 제공한다.

 createElement 1번째 매개변수 tpye의 타입은 Functioncomponent<P>, ComponentClass<P>, string 중 하나일 수 있다.
  2번째 매개변수는 props 변수 이름 뒤에 ?가 붙었으므로 생략가능한 선택 매개변수이다.  따라서 <p>요소 생성은 다음처럼 생성할 수 있다.

import React from 'react'
import ReactDOM from 'react-dom/client'

// 물리DOM 버전을 리액트 프레임워크를 통해 가상DOM으로 객체 생성
const pPhysicalDOM = React.createElement('p', null, 'Hello virtual DOM world!')

// document.getElementById는 id 속성값이 'root'인 DOM객체를 찾아낸다.
const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement)

// pPhysicalDOM 가상DOM 트리를 물리DOM트리로 변환(렌더링)해준다.
root.render(pPhysicalDOM)

  가상DOM은 document.body.appendChild를 통해 추가할 수 있는 DOM객체가 아니다.  따라서 다른 방법인 root.render(pVirtualDOM) 을 통해 가상 DOM객체를 화면에 렌더링한다.  root.render 메서드는 가상 DOM 객체를 부착(append)할 물리 DOM 객체가 필요하다.