Skip to content

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)합니다.

  1. 현재 컴포넌트에 스케줄링된 Work가 없는 상태
  2. 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)해봅니다. 바뀔 것이 없다면 렌더링을 시작조차 하지 않고 그 자리에서 종료합니다.

참고자료 ​