React UI 업데이트 프로세스: 트리거에서 커밋까지
React는 일련의 단계를 통해 인터페이스를 업데이트합니다: 트리거 → 렌더링 → 커밋. 렌더링 단계에서는 실제 DOM을 건드리지 않고 새로운 가상 DOM 트리를 계산합니다. 커밋 단계에서는 변경 사항을 동기적으로 적용합니다. 이 분리는 성능 최적화를 가능하게 하며, 특히 동시 모드에서는 우선순위에 따라 렌더링이 중단될 수 있습니다.
렌더링 단계: 재조정과 파이버 트리
렌더링 단계는 현재 파이버 구조를 기반으로 작업 중인 트리를 생성합니다. 파이버는 컴포넌트 계층을 나타내는 노드들의 연결 리스트입니다. 각 노드는 alternate 속성을 통해 이전 버전을 참조하여 비교(디핑)를 수행합니다.
재조정은 JSX로부터 생성된 새 React 요소와 기존 요소를 비교합니다. 안정적인 key 값은 정확한 매칭을 보장하며, 불필요한 업데이트를 최소화합니다.
이 단계는 두 단계로 나뉩니다: beginWork(상향식)과 completeWork(하향식):
- beginWork: 렌더링이 필요한지 확인(필요 없으면 중단), 렌더 함수 호출, 플래그(Placement, Update, Deletion) 설정, 자식 요소로 재귀 호출.
- completeWork: 자식 요소 처리 후 노드를 완료하고, 서브트리 플래그를 집계하여 커밋 최적화.
서브트리 플래그는 변경 정보를 위로 전파하며, 커밋 시 깨끗한 브랜치는 건너뜁니다.
| 플래그 | 설명 |
|------|-------------|
| Placement | DOM 노드 삽입 |
| Update | 속성 또는 텍스트 업데이트 |
| Deletion | 요소 삭제 |
| Ref | refs 처리 |
| Layout | useLayoutEffect 예약 |
| Passive | useEffect 예약 |
플래그는 렌더링 단계에서 설정되며, 커밋 단계에서 실행됩니다.
커밋 단계: DOM 변형
커밋 단계는 동기적이며 원자적입니다. 세 가지 하위 단계로 나뉩니다:
- beforeMutation: 클래스 컴포넌트용
getSnapshotBeforeUpdate호출 및 오래된 refs 정리. - mutation: 플래그를 적용해 DOM 노드 삽입, 업데이트 또는 삭제.
- layout:
componentDidMount/Update,useLayoutEffect를 동기적으로 실행, refs 업데이트,useEffect예약.
layout 이후 브라우저가 다음 단계를 처리합니다: 스타일 재계산 → 레이아웃/리플로우 → 렌더링 → 병합. React는 이 과정에 간섭하지 않습니다.
커밋 이후 브라우저 파이프라인
useEffect는 렌더링 이후 비동기적으로 실행되지만, 클릭, 키다운, 입력과 같은 디스크리트 이벤트의 경우 반응성을 유지하기 위해 렌더링 전에 실행될 수 있습니다.
디스크리트 이벤트:
- click, keydown, input, submit
연속 이벤트(scroll, mousemove)는 항상 렌더링 후에 실행됩니다.
동시 모드: 중단 가능한 렌더링
동시 모드에서는 렌더링이 우선순위가 있는 작업 단위로 나뉩니다. 높은 우선순위 업데이트(예: 타이핑)는 낮은 우선순위 업데이트(이전 렌더링)를 중단할 수 있으며, 작업 중인 트리는 폐기됩니다.
커밋은 그대로 유지됩니다: 동기적이고 하나의 업데이트당 한 번만 실행됩니다. 이는 DOM 일관성을 보장합니다.
업데이트가 중단되면 렌더링은 여러 번 재시작할 수 있지만, 커밋은 발생하지 않습니다.
핵심 요약
- 렌더링은 메모리에서 변화를 계산하며, DOM 변형은 커밋 시 플래그가 있을 때만 발생합니다.
beginWork/completeWork는 중단과 서브트리 플래그를 활용해 탐색을 최적화합니다.useLayoutEffect는 변형 후 동기적으로 실행되며,useEffect는 렌더링 후 비동기적으로 실행됩니다.- 동시 모드에서는 렌더링을 중단할 수 있지만, 커밋은 분리 불가능합니다.
- 안정적인 key 값은 효율적인 재조정에 필수적입니다.
— Editorial Team
아직 댓글이 없습니다.