React_Deep_Dive_3_가상 DOM과 리액트 파이버

조용환·2024년 1월 18일
0

React_Deep_Dive

목록 보기
3/12

DOM과 브라우저 렌더링 과정

  • 브라우저가 사용자가 요청한 주소를 방문해 HTML 파일을 다운로드한다.
  • 브라우저의 렌더링 엔진은 HTML을 파싱해 DOM 노드로 구성된 트리(DOM)을 만든다.
  • 2번 과정에서 CSS파일을 만나면 해당 CSS 파일도 다운로드한다.
  • 브라우저의 렌더링 엔진은 이 CSS도 파싱해 CSS 노드로 구성된 트리(CSSOM)을 만든다.
  1. 브라우저는 2번에서 만든 DOM 노드를 순회하는데, 여기서 모든 노드를 방문하는 것이 아니고 사용자 눈에 보이는 노드만 방문한다. 즉, display: none과 같이 사용자 화면에 보이지 않는 요소는 방문해 작업하지 않는다. 이는 트리를 분석하는 과정을 조금이라도 빠르게 하기 위해서.
  • 5번에서 제외된 눈에 보이는 노드를 대상으로 해당 노드에 대한 CSSOM 정보를 찾고 여기서 발견한 CSS 스타일 정보를 이 노드에 적용한다. 이 DOM 노드에 CSS를 적용하는 과정은 크게 2가지다.
  • 레이아웃 : 각 노드가 브라우저 화면의 어느 좌표에 정확히 나타나야 하는지 계산하는 과정. 이 과정을 거치면 반드시 페인팅 과정도 거침
  • 페인팅: 레이아웃 단계를 거친 노드에 색과 같은 실제 유효한 모습을 그리는 과정.

가상DOM

가상 DOM에 대해 가지고 있는 한 가지 일반적인 오해는 리액트의 이러한 방식이 일반적인 DOM을 관리하는 브라우저보다 빠르다는 사실이다. 이는 리액트 개발자인 댄 아브라모프(dan_abramov)가 사실이 아니라고 부정한 바 있다. 무조건 빠른 것이 아니라 가상 DOM 방식은 대부분의 상황에서 왠만한 app을 만들 수 있을 정도로 충분히 빠르다는 것이다.

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

리액트 파이버란?

리액트에서 관리하는 평범한 자바스크립트 객체. 파이버는 파이버 재조정자(fiber reconciler)가 관리하는데, 이는 가상 DOM과 실제 DOM을 비교해 변경 사항을 수집하며, 둘 사이에 차이가 있으면 변경에 관련된 정보를 가지고 있는 파이버를 기준으로 화면에 렌더링을 요청하는 역할을 함.
재조정(reconciliation) : 가상 DOM과 실제 DOM을 비교하는 작업(알고리즘)

리액트 파이버가 하는 일

  • 작업을 작은 단위로 분할하고 쪼갠 다음, 우선순위를 매김.
  • 이러한 작업을 일시 중지하고 나중에 다시 시작할 수 있음
  • 이전에 했던 작업을 다시 재사용하거나 필요하지 않은 경우에는 폐기할 수 있음
  • 이러한 모든 과정이 비동기로 일어남.
  • 과거에는 스택 조정자 였으나 효율성 증대를 위해 fiber의 등장으로 이어짐

파이버 구현 방식

  • 파이버는 하나의 작업 단위로 구성
  • finishedWork()라는 작업으로 마무리
  • 커밋을 통해 브라우저 DOM에 가시적인 변경 사항을 만들어 냄
    - 렌더 단계에서 리액트는 사용자에게 노출되지 않는 모든 비동기 작업을 수행
    • 위의 단계에서 앞서 언급한 파이버의 작업, 우선순위를 지정하거나 중지시키거나 버리는 등의 작업이 일어남.
    • 커밋 단계에서는 앞서 언급한 것처럼 DOM에 실제 변경 사항을 반영하기 위한 작업, commitWork()가 실행
    • 위의 단계는 동기적으로 일어나며 중단될 수도 없다.
  • 파이버는 단순한 자바스크립트 객체로 구성되어 있음.
  • 파이버는 컴포넌트가 최초로 마운트되는 시점에 생성되며, 리액트 요소와 다르게 렌더링이 발생될 때 마다 새롭게 생성되지 않고, 가급적 재사용 함.
  • 파이버의 객체 값에서도 알 수 있듯이 리액트의 핵심 원칙은 UI를 문자열, 숫자, 배열과 같은 값으로 관리함.

리액트 파이버 트리

파이버 트리는 두 가지 종류임. 1. 현재 모습을 다음 파이버 트리. 2. 작업중인 상태를 나타내는 workInProgress 트리
리액트 파이버의 작업이 끝나면 리액트는 단순히 포인터만 변경해서 workInProgress 트리를 현재 트리로 바꿈. 이러한 기술을 더블 버퍼링이라고 함. (컴퓨터 그래픽 분야에서 사용되는 용어)

파이버의 작업 순서

일반적인 파이버 노드의 생성 흐름은 다음과 같다.
1. 리액트는 beginWork() 함수를 실행해 파이버 작업을 수행하는데, 더 이상 자식이 없는 파이버를 만날 때까지 트리 형식으로 시작
2. 1번에서 작업이 끝난다면 그다음 completeWork() 함수를 실행해 파이버 작업을 완료함
3. 형제가 있다면 형제로 넘어감
4. 2번, 3번이 모두 끝났다면 return으로 돌아가 자신의 작업이 완료됐음을 알림

<A1>
  <B1>안녕하세요</B1>
  	<B2>
  		<C1>
  		<D1 />
 		<D2 />
  	</C1>
  </B2>
  <B3 />
</A1>

위 작업은 JSX 코드에서 다음과 같이 수행된다.

- A1의 beginWork()가 수행
- A1은 자식이 있으므로 B1로 이동해 beginWork()를 수행
- B1은 자식이 없으므로 completeWork()가 수행. 자식은 없으므로 형제인 B2로 넘어감
- B2의 beginWork()가 수행. 자식이 있으므로 C1로 이동
- C1의 beginWork()가 수행. 자식이 있으므로 D1로 이동
- D1의 beginWork()가 수행
- D1은 자식이 없으므로 completeWork()가 수행. 형제인 D2로 이동
- D2는 자식이 없으므로 beginWork() 수행
- D2는 자식, 형제 없으므로 위로 이동해 D1, C1, B2 순으로 completeWork() 호출
- B2는 형제인 B3로 이동 beginWork() 수행
- B3의 completeWork()가 수행되면 반환해 상위로 타고 올라감
- A1의 completeWork()가 수행.
- 루트 노드 완성되는 순간 최종적으로 commitWork() 수행되고 이 중에 변경 사항을 비교해 업데이트가 필요한 변경 사항이 DOM에 반영

이후 리렌더링 시에는 이미 있는 파이버를 재사용한다.

파이버와 가상 DOM

리액트 컴포넌트에 대한 정보를 1:1로 가지고 있는 것이 파이버이며, 이 파이버는 리액트 아키텍처 내부에서 비동기로 이뤄짐.
실제 브라우저 구조인 DOM에 반영하는 것은 동기적으로 일어나야 하고, 또 처리하는 작업이 많아 불완전하게 표시할 가능성이 높기 때문에 이러한 작업을 가상에서 먼저 수행해 최종적인 결과물만 실제 브라우저 DOM에 적용하는 것.
가상 DOM이라는 표현을 계속 썼지만, 이는 오직 Web app에서만 통용되는 개념이다. 리액트 파이버는 리액트 네이티브와 같은 브라우저가 아닌 환경에서도 사용할 수 있기 때문에 파이버와 가상 DOM은 동일한 개념이 아니다.
리액트와 리액트 네이티브의 렌더러가 서로 다르다 하더라도 내부적으로 파이버를 통해서 조정되는 과정은 동일하기 때문에 동일한 재조정자를 사용할 수 있게 된다.

정리

가상 DOM과 리액트의 핵심은 브라우저의 DOM을 더욱 빠르게 그리고 반영하는 것이 아니라 바로 값으로 UI를 표현하는 것. 또한 이러한 흐름을 효율적으로 관리하기 위한 메커니즘이 바로 리액트의 핵심이다.

profile
practice react, javascript

0개의 댓글