React Fiber Architecture
January 20, 2025
React Element and Fiber Node
리액트의 렌더링 과정은 리액트 엘리먼트에서 시작합니다. 리액트 엘리먼트는 임시적이고 상태가 없습니다. 반면 파이버 노드는 상태를 저장하고 수명이 깁니다.
createFiberFromTypeAndProps
함수를 통해서 리액트 엘리먼트로부터 파이버 노드를 생성합니다.
이렇게 생성된 파이버 노드는 실제 작업 단위로, 리액트의 내부 인스턴스와 연결됩니다.
Render Phase
리액트는 work loop를 통해 사용자 인터페이스를 업데이트합니다.
이 과정에서 beginWork
는 파이버 트리를 순회하면서 업데이트가 필요한 컴포넌트를 찾고 더티 체크를 수행합니다.
트리 끝에 도달하면 completeWork
함수를 실행해서 반대로 순회하면서 새 가상 DOM을 생성합니다.
이 때에는 실제 DOM을 조작하는 것처럼 DOM 엘리먼트를 추가하는 등의 작업을 수행합니다.
이렇게 오프스크린 렌더링 프로세스 기술을 이용해 현재 화면에 영향을 미치지 않고 화면을 업데이트하는 것을 렌더링 과정이라 합니다. 렌더링 과정은 비동기적이며 중단/취소될 수 있습니다.
Commit Phase
백그라운드에서 업데이트된 가상 DOM을 실제 화면에 반영하는 과정을 커밋 과정이라고 합니다. 커밋 과정은 동기적이라 취소가 불가능합니다.
커밋 과정은 두 단계로 나뉩니다.
- 변형 단계(Mutation): 실제 DOM을 조작하는 행위를 수행합니다. DOM을 추가하거나 삭제 또는 위치 조정 등의 역할을 수행합니다.
- 레이아웃 단계(Layout): DOM 변경 후 레이아웃 계산을 수행합니다.
React Scheduler and Concurrent Mode
"백그라운드"라는 말은 자바스크립트 환경에는 맞지 않습니다. 자바스크립트 엔진은 싱글스레드이기 때문입니다.
그래서 리액트 스케줄러는 Time Slicing 기법을 사용해 약 5밀리초마다 메인 스레드에게 제어권을 넘겨주어 화면이 멈추지 않도록 구현했습니다.
렌더링 과정 중에 유저의 클릭 이벤트와 같은 우선순위가 높은 작업이 발생하면 현재 렌더링이 폐기되고 우선순위가 높은 작업이 수행됩니다.
Effect 처리
커밋 과정에서 effect와 passive effect가 존재합니다.
-
Effect: 브라우저의 페인팅 이전 시점에 실행되는 작업입니다.
useLayoutEffect
가 여기에 해당합니다. -
Passive Effect: 브라우저 페인팅이 일어난 후에 실행되는 작업입니다.
useEffect
가 여기에 해당합니다. -
useLayoutEffect
: DOM 측정과 같이 화면 그리기 전에 필요한 작업에 사용됩니다. -
useEffect
: 네트워크 요청과 같이 화면 업데이트를 지연시키지 않아도 되는 작업에 사용됩니다.
최적화란 어디까지 의미가 있나
리액트의 렌더링이란 실제 화면에 반영되는 과정이 아니며 리액트 내부에서 오프스크린 렌더링으로 동작하며 언제든지 중단 될 수 있습니다.
그렇기에 리렌더링 되는것이 반드시 화면 성능에 영향을 주는 것이 아니며
일차적으로 beginWork 과정에서 실제 변경이 필요한 엘리먼트가 더티 체크되고 completeWork 과정에서 변경사항이 업데이트 됩니다.
그러나 오프스크린 렌더링 방식으로 실제 DOM에 영향을 주지 않더라도 엘리먼트가 많아지고 많은 리렌더링이 발생하면 불필요한 더티체크 연산이 발생할 수 있습니다.
그렇기에 복잡하고 많은 DOM 엘리먼트를 가진 화면에서 렌더링 과정의 최적화는 필요합니다. 특히 모바일 환경에서는 불필요한 연산이 빠른 배터리 소모로 이어질 수 있습니다.