React RN-렌더링 워크플로우
Source: Dev.to
개요
이 글에서는 React 재렌더링 워크플로우에 대한 개인적인 분석을 공유합니다. 이 과정은 세 가지 핵심 단계(플러스 브라우저 페인팅)로 구성됩니다. 각 단계에 대한 간단한 설명은 다음과 같습니다.
단계 1 – 트리거
React는 상태가 변할 때 렌더링을 시작합니다. 예시:
- 상태(state) 변경
- props 변경
- 컨텍스트(context) 변경
- 부모 컴포넌트 재렌더링
Note: React는 DOM을 즉시 업데이트하지 않고, 업데이트를 스케줄링만 합니다.
단계 2 – 렌더 단계
Fiber 엔진이 이 단계에서 조정(reconciliation)을 수행합니다:
- 컴포넌트를 호출하고 새로운 React 요소(Virtual DOM)를 생성
- 새로운 출력과 이전 출력을 비교(디핑)
- 어떤 부분을 업데이트, 삭제, 생성해야 할지 결정
Note: 이 단계는 순수 계산 단계이며, DOM 변형은 일어나지 않습니다.
단계 3 – 커밋 단계
렌더 단계가 끝난 뒤 커밋 단계가 실행되며 중단할 수 없습니다. React가 최종 변경 사항을 확보하면 실제 DOM을 업데이트합니다:
- DOM 변형이 발생
- refs가 업데이트
- 이전 이펙트의 정리(cleanup) 실행
useLayoutEffect가 동기적으로 실행되어 브라우저 페인팅 전에 수행
Note: 이 단계는 빠르지만 차단(blocking)됩니다.
단계 4 – 브라우저 페인팅
DOM이 업데이트되면 브라우저가 화면에 UI를 그립니다. 페인팅이 끝난 뒤:
useEffect가 비동기적으로, 비차단 방식으로 실행
그래서
useEffect는 UI를 차단하지 않지만,useLayoutEffect는 차단할 수 있습니다.
예시
function Counter() {
const [count, setCount] = useState(0);
return (
<button onClick={() => setCount(count + 1)}>
{count}
</button>
);
}
버튼을 클릭했을 때:
- 트리거:
setCount가 호출됩니다. - 렌더 단계: React가 새로운 요소를 만들고 이전 요소와 비교합니다.
- 커밋 단계: 버튼 텍스트가 실제 DOM에 업데이트됩니다.
- 브라우저 페인팅: UI에 새로운 카운트가 표시됩니다.
useEffect(존재한다면)가 페인팅 후에 실행됩니다.
출력이 변하지 않으면 React는 DOM 업데이트를 건너뛸 수 있습니다(최적화).
중요한 포인트
- 재렌더링이 항상 DOM 업데이트를 의미하는 것은 아닙니다.
- 부모의 재렌더링은 자식의 재렌더링을 트리거할 수 있습니다.
- React는 여러 상태 업데이트를 배치(batch)합니다.
- 리스트 렌더링에서는
key가 중요합니다. - Strict Mode에서는 개발 환경에서만 컴포넌트를 두 번 렌더링할 수 있습니다.
- 렌더 단계는 여러 번 실행될 수 있지만, 커밋 단계는 업데이트당 한 번만 실행됩니다.