Commit Phase
실제 DOM 반영
커밋 단계에서 React는 렌더 단계가 계산한 변경(effect list)을 실제 DOM에 반영한다. 동기적으로, 한 번에.
커밋 단계(Commit Phase)는 렌더 단계가 계산해 낸 work-in-progress 트리의 변경 사항을 실제 DOM에 반영하는 단계로, 중단 불가능한 동기(synchronous) 실행이 특징이다. 내부적으로 세 개의 하위 단계로 나뉜다: before mutation(변이 전, getSnapshotBeforeUpdate 호출 등 DOM 변이 직전 상태를 읽는 단계), mutation(실제 DOM 삽입·삭제·속성 갱신 및 이전 ref detach, useLayoutEffect의 cleanup 실행), layout(DOM 변이 완료 후 useLayoutEffect의 create 실행 및 새 ref attach). 이 세 단계는 브라우저 페인트 이전에 동기적으로 끝나므로, useLayoutEffect에서 DOM을 측정하고 다시 쓰면 사용자는 깜빡임 없이 최종 결과만 본다. 반면 useEffect(passive effect)는 커밋과 페인트가 끝난 뒤 별도로 비동기 스케줄되어 실행되므로 페인트를 막지 않는다. 트리 스왑(work-in-progress 트리가 current 트리가 됨, root.current = finishedWork)은 mutation 단계와 layout 단계 '사이'에서 일어나며 — 그래서 layout 단계의 useLayoutEffect create·componentDidMount는 이미 새 트리를 current로 본다 — 세 하위 단계가 모두 끝난 뒤에야 브라우저가 화면을 다시 그릴 기회를 얻는다.
내부 구성
핵심 포인트
- 커밋 단계는 동기적이고 중단 불가능하다 — 렌더 단계와 달리 절대 쪼개지거나 폐기되지 않는다
- 3개 하위 단계: before mutation → mutation → layout 순서로 실행된다
- before mutation: getSnapshotBeforeUpdate 호출 등 DOM을 변경하기 직전의 스냅샷을 읽는다
- mutation: 실제 DOM에 노드 삽입/삭제/갱신, 이전 ref를 null로 detach, useLayoutEffect의 cleanup(destroy) 실행
- layout: DOM 반영이 끝난 뒤 useLayoutEffect의 create 콜백을 동기 실행하고 새 ref를 attach — 페인트 전이라 측정+재조정이 안전
- useLayoutEffect는 페인트를 막고 동기 실행(깜빡임 방지), useEffect(passive)는 페인트 후 비동기 실행(성능 우선)
- 트리 스왑(work-in-progress → current)은 mutation 단계 뒤·layout 단계 앞에서 일어나(그래서 layout 단계 콜백은 새 트리를 봄), 세 하위 단계가 끝난 뒤 브라우저가 페인트한다
심화
실무·면접에서 가장 중요한 통찰은 '왜 useLayoutEffect는 페인트 전, useEffect는 페인트 후인가'다. useLayoutEffect는 mutation과 함께 커밋의 layout 단계에서 동기 실행되므로, 여기서 DOM을 측정하고 스타일을 다시 쓰면 그 재조정까지 모두 하나의 프레임 안에서 끝나 사용자는 중간 상태를 보지 못한다(툴팁 위치 보정, 스크롤 복원 등 레이아웃 측정에 필수). 대가는 페인트를 지연시키므로 무거운 작업을 넣으면 인터랙션이 버벅인다. 반면 useEffect는 페인트 후 비동기라 데이터 페칭·구독·로깅 등 화면과 무관한 부작용에 적합하다. 덜 알려진 디테일: cleanup의 실행 순서가 정확성을 좌우한다. 커밋 시 모든 관련 Fiber의 destroy(cleanup)가 먼저 전부 호출된 뒤에야 create가 호출된다 — 형제 컴포넌트 간 정리와 생성이 뒤섞여 서로의 이미 해제된 상태를 참조하는 버그를 막기 위함이다. 또한 useEffect는 '비동기'지만 사용자에게 시각적 갱신을 커밋하기 전에 이전 렌더의 passive effect를 flush하도록 보장되는 경우가 있어, 완전히 게으른 것은 아니다. React 18의 자동 배칭(automatic batching)은 여러 setState를 하나의 렌더+커밋으로 묶어 이 전체 파이프라인을 한 번만 돌게 만든다는 점도 함께 이해해야 한다.
쉽게 말하면 확정된 설계 변경을 실제 건물에 한 번에 시공하는 단계.