8. Idle과 Render 페이즈
이번 챕터에선 Idle과 Render 상태의 차이와 식별하는 기준에 대해 분석합니다.
- Idle 상태: 현재 어떤 렌더링 작업도 진행되지 않는 상태
- Render 페이즈: 변경 사항을 계산하며 Fiber 트리를 구축 중인 상태
1. 페이즈를 구분하는 기준: isRenderPhaseUpdate
React 엔진 내부(Reconciler)는 현재 작업 중인 Fiber 노드를 추적하며, 이를 통해 현재 페이즈를 판단합니다.
jsx
// /react/packages/react-reconciler/src/ReactFiberHooks.js
function isRenderPhaseUpdate(fiber: Fiber): boolean {
const alternate = fiber.alternate;
return (
fiber === currentlyRenderingFiber ||
(alternate !== null && alternate === currentlyRenderingFiber)
);
}반환값에 따라 아래와 같이 구분됩니다.
true→ Render 페이즈에서 발생한 업데이트false→ Idle 상태에서 발생한 업데이트
왜 두 번 비교하나요?
React는 더블 버퍼링(Double Buffering) 구조를 사용하기 때문입니다. 현재 화면에 보이는 current 트리와 메모리에서 작업 중인 alternate 트리, 이 둘 중 하나라도 현재 렌더링 중인 Fiber와 일치한다면 렌더링 도중에 발생한 업데이트로 간주합니다.
2. 상태에 따른 업데이트 전략: dispatchSetStateInternal
사용자가 setState를 호출하면, 내부적으로 dispatchSetStateInternal 함수가 실행됩니다. 이 함수는 현재 페이즈에 따라 서로 다른 최적화 경로를 선택합니다.
2.1. Idle 상태 업데이트
컴포넌트가 쉬고 있을 때 업데이트가 들어오면, React는 렌더링을 시작하기 전에 먼저 결과를 미리 계산(Eager Calculation)해봅니다. 다음 두 조건이 모두 충족되면 렌더링을 아예 시작하지 않고 중단(Bailout)합니다.
- 현재 컴포넌트에 스케줄링된 Work가 없는 상태
- action의 결괏값이 현재 상태 값과 동일한 경우
jsx
// /react/packages/react-reconciler/src/ReactFiberHooks.js
function dispatchSetStateInternal<S, A>(fiber, queue, action, lane) {
if (isRenderPhaseUpdate(fiber)) {
// 렌더 상태의 업데이트는 다음 챕터에서 설명합니다.
...
} else {
// [Idle 상태] 불필요한 렌더링을 막기 위한 최적화 검사
if (queue.lanes === NoLanes && (alternate === null || alternate.lanes === NoLanes)) {
const lastRenderedReducer = queue.lastRenderedReducer;
if (lastRenderedReducer !== null) {
try {
const currentState: S = (queue.lastRenderedState: any);
const eagerState = lastRenderedReducer(currentState, action);
// 새로운 상태(eagerState)가 현재 상태(currentState)와 같은지 확인
if (is(eagerState, currentState)) {
// 스케줄링을 하지 않고 종료
// 렌더링 단계를 아예 시작조차 하지 않음으로써 자원을 절약함
return;
}
} catch (error) {
...
}
}
}
// 값이 다르다면 스케줄러에 렌더링 작업을 예약
const root = enqueueConcurrentHookUpdate(fiber, queue, update, lane);
if (root !== null) {
scheduleUpdateOnFiber(root, fiber, lane);
}
}
}React는 Idle 상태에서 setState가 호출될 때, 렌더링 엔진을 가동하기 전에 미리 결과값을 계산(Eager Calculation)해봅니다. 바뀔 것이 없다면 렌더링을 시작조차 하지 않고 그 자리에서 종료합니다.