heyday2024 님의 블로그
[React 2주차 (4)] 컴포넌트 & 렌더링, DOM vs Virtual DOM 본문
Compoment
컴포넌트는 리액트의 핵심 빌딩 블록 중 하나
==> 리액트에서 개발할 모든 애플리케이션은 컴포넌트라는 조각으로 구성됨.
컴포넌트는 UI 구축 작업을 훨씬 쉽게 만들어주기 때문에 사용함.
- 재사용 가능
UI 요소를 표현하는 최소한의 단위이며 화면의 특정 부분이 어떻게 생길지 정하는 선언체임!
리액트의 컴포넌트기반 개발 이전에는 브라우저에서 동적으로 변하는 UI를 표현하기 위해 직접 DOM 객체를 조작하는 명령형 프로그래밍 방식으로 구현
<선언형 프로그래밍 방식 vs 명령형 프로그래밍 방식>
1. DOM (명령형 프로그래밍): 프로그래머가 컴퓨터에게 "어떻게" 작업을 수행할지를 명시적으로 지시하는 스타일
// Hello, World! 화면에 출력하기
// 순수 javaScript 명령형 코드
const root = document.getElementById('root');
const header = document.createElement('h1');
const headerContent = document.createTextNode(
'Hello, World!'
);
header.appendChild(headerContent);
root.appendChild(header);
- 수행 절차를 일일히 코드로 작성함.
- 성능 최적화 가능함: 메모리 관리와 성능 직접 조절 가능
- 하지만, 복잡한 UI 시스템에서는 관리가 너무 어려워짐.
- 코드 재사용성 낮음
2. 리액트(선언형 프로그래밍) : 프로그래머가 "무엇"을 할지를 명시하고, 구체적인 작업 수행 방법에 대해서는 신경 쓰지 않는 스타일.
// React 코드 (선언적인)
const header = <h1>Hello World</h1>; // jsx
ReactDOM.render(header, document.getElementById('root'));
- UI를 선언하고, render 함수 호출하면 React가 알아서 절차를 수행해 화면에 출력해줌.
- 가독성, 재사용성 좋음
- 상태 변화를 명시하지 않고 원하는 결과를 선언하는 방식이어서 복잡성이 줄어듦
- 세부적인 흐름 제어가 쉽지 않을 수 있고, 번들 요량이 큼.
Rendering
리액트에서 렌더링이란, 컴포넌트가 현재 props와 state의 상태에 기초하여 UI를 어떻게 구성할지 컴포넌트에게 요청하는 작업을 의미.
<렌더링이 일어나는 순서>
1. 렌더링 일으키는 것은 (triggering)- UI를 주문하고 주방으로 전달하는 것
- 첫 리액트 앱을 실행했을 때
- 현재 리액트 내부에 어떤 상태(state)에 변경이 발생했을 때.
- 컴포넌트 내부 state가 변경되었을 때
- 컴포넌트에 새로운 props가 들어올 때,
- 상위 부모 컴포넌트에서 위에 두 이유로 렌더링이 발생했을 때 (--> 자식까지 영향)
==> 리액트 앱이 실행되고 첫 렌더링이 일어나면 리액트는 컴포넌트의 루트에서 시작하여 아래쪽으로 쭉 훑으며 컴포넌트가 반환하는 JSX 결과물을 DOM 요소에 반영
2. 렌더링한다는 것은 (rendering)- 주방에서 컴포넌트가 UI를 만들고 준비하는 것
3. 렌더링 결과는 실제 DOM에 커밋한다는 것은 (commit) - 리액트가 준비된 UI를 손님 테이블에 올려놓는 것
<리렌더링 Rerendering>
첫 렌더링은 자동으로 일어난 것이지만,
앞서 트리거가 발생되는 조건에 의해(컴포넌트 상태 변화), 다시 렌더링됨.
==> 이때 여러 상태가 변경되었다면, 이를 리액트는 큐 자료구조에 넣어 순서를 관리함. 그래서 바뀔 때마다 리렌더링을 하기보단 한꺼번에 바뀐 내용을 리렌더링해줌.
리렌더링 과정 정리:
- 상태 변화 감지: 컴포넌트의 상태가 변경되면, React는 이를 감지함. 이 상태 변화는 사용자 입력, API 응답, 타이머 등 다양한 트리거에 의해 발생할 수 있음.
- 큐에 추가: 여러 상태가 한 번에 변경되면, React는 이러한 변경사항을 큐에 넣어 순서를 관리함. 이렇게 하면, 매번 상태가 변경될 때마다 리렌더링을 하지 않고, 필요한 경우 한꺼번에 업데이트를 처리할 수 있음. 이로 인해 성능이 향상됨.
- 최적화된 리렌더링: React는 상태 변화가 발생한 후, 필요 없는 리렌더링을 피하기 위해 Virtual DOM을 사용함. 변경된 부분만 실제 DOM에 업데이트함으로써, 리렌더링 과정이 더욱 효율적으로 이루어짐.
참고로,
브라우저의 렌더링과 리액트의 렌더링은 엄연히 다른 독립적인 프로세스
렌더링이 완료되고 React가 DOM을 업데이트한 후 브라우저는 화면을 그림.
이 프로세스를 "브라우저 렌더링"이라고 하지만 혼동을 피하기 위해 "페인팅"이라고함.
DOM 과 Virtual DOM
리액트(react.js)나, 뷰(Vue.js)는 가상돔(Virtual DOM)을 사용해서 원하는 화면을 브라우저에 그려줌.
자체적으로 상당히 효율적인 알고리즘을 사용해서 그려주기 때문에 그 속도가 매우 빠름.
<DOM(Document Object Model)>
수 많은 컴포넌트로 구성된 웹페이지들을 보면, 그 페이지를 문서(document)라고 하고, 그 페이지를 이루는 컴포넌트를 엘리먼트(element)라고함.
==> DOM은 이 엘리먼트를 tree 형태(DOM Tree)로 표현한 것!!
트리의 요소 하나하나를 Node라고 하고, 각각의 노드는 해당 노드에 접근, 제어를 할 수 있는 API(HTML 요소에 접근해서 수정할 수 있는 함수)를 제공함.
// id가 demo인 녀석을 찾아, 'Hello World!'를 대입해줘.
document.getElementById("demo").innerHTML = "Hello World!";
// p 태그들을 모두 가져와서 element 변수에 저장해줘
const element = document.getElementsByTagName("p");
// 클래스 이름이 intro인 모든 요소를 가져와서 x 변수에 저장해줘
const x = document.getElementsByClassName("intro");
<가상DOM(Virtual DOM)>
리액트는 가상DOM을 이용해서 실제DOM을 변경하는 작업을 상당히 효율적으로 수행함.
==> 가상 DOM은 실제 DOM의 가벼운 복사본.
==> 실제 DOM은 아니지만, 객체(object) 형태로 메모리에 저장되기 때문에 실제 DOM을 조작하는 것 보다 훨씬 더 빠르게 조작을 수행할 수 있음
==> 실제 DOM을 조작하는 것보다, 메모리상에 올라와있는 javascript 객체를 변경하는 작업이 훨씬 더 가볍답니다!
<DOM 조작 과정: 가상 돔>
이벤트가 발생했을 때(state가 변경되었을 때), 해당 엘리먼트 DOM 요소가 갱신되는 과정
[STEP 1]
이 과정에서 리액트는 항상 **2가지 버전의 가상DOM**을 가지고 있어요.
- 화면이 갱신되기 전 구조가 담겨있는 가상DOM 객체
- 화면 갱신 후 보여야 할 가상 DOM 객체
리액트는 state가 변경돼야만 리렌더링이 되죠. 그 때, 바로 2번에 해당되는 가상 DOM을 만드는거죠.
[STEP 2 : diffing]
state가 변경되면 2번에서 생성된 가상돔과 1번에서 이미 갖고있었던 가상돔을 비교해서 어느 부분(엘리먼트)에서 변화가 일어났는지를 상당히 빠르게 파악함.
[STEP 3 : 재조정(reconciliation)]
파악이 다 끝나면, 변경이 일어난 그 부분만 실제 DOM에 적용시켜줌. 적용시킬 때는, 한건 한건 적용시키는 것이 아니라, 변경사항을 모두 모아 한 번만 적용을 시킴. (Batch Update)
<Batch Update>
변경된 모든 엘리먼트를 한꺼번에 반영할 수 있는 방법
--> 우선순위 큐 사용: React는 변화된 상태와 DOM 업데이트 작업을 우선순위에 따라 큐에 쌓아두고, 브라우저가 작업할 수 있는 시점에 한꺼번에 처리합니다.
<클릭 한 번으로 화면에 있는 5개의 엘리먼트가 바뀌어야 한다면>
- 실제 DOM : 5번의 화면 갱신 필요
- 가상 DOM : Batch Update로 인해 단 한번만 갱신 필요 (훨씬 효율적!!)
==> 이런 과정을 거쳐서 결국 변경된 사항이 브라우저에 렌더링(페인팅)됨.
- 스타일 계산: HTML과 CSS를 분석하여 각 요소의 스타일을 계산합니다.
- 레이아웃: 각 요소의 위치와 크기를 계산합니다.
- 페인팅: 레이아웃 단계에서 계산된 정보를 바탕으로 요소를 화면에 그립니다.
'프론트엔드 부트캠프' 카테고리의 다른 글
[React] 올림픽 메달 추적: 개인 프로젝트 정리(2) (0) | 2024.11.01 |
---|---|
[React 개인과제] 올림픽 메달 트래커 만들어보기 (1) | 2024.10.31 |
[React 2주차 (3)] 컴포넌트와 JSX, props, state (1) | 2024.10.30 |
[React 2주차(2)] 프로젝트 생성 (2) | 2024.10.29 |
[React 2주차(1)] React: SPA (0) | 2024.10.29 |