react · high priority
React Fiber — 중단·재개 가능한 재조정 엔진
Stack Reconciler 가 풀지 못한 응답성 문제와 Fiber 의 해법
학습 개요
탄생 배경
쉬운 설명
복잡한 개념을 실생활 비유로 설명합니다.
“레스토랑의 새 주방장과 주문 보드”
예전 주방(Stack Reconciler)은 한 번에 한 주문만 받아 끝까지 만들었습니다. 코스 주문이 들어오면 손님이 마실 물도 그동안 못 내갔죠. 새 주방장(Fiber)은 모든 주문을 *주문 보드*(Fiber 트리) 에 적어두고, 짧은 단위로 이 주문 → 저 주문을 옮겨다닙니다. VIP 가 들어오면(높은 우선순위) 만들던 코스를 잠시 미뤄 그쪽 음료부터 갑니다. 손님이 갑자기 메뉴를 바꾸면 만들던 접시를 버리고(work-in-progress 폐기) 새 주문을 시작합니다.
핵심 개념
Stack vs Fiber Reconciler
- 재귀 호출 스택이 곧 작업 진행 상태
- 중단 불가 → 큰 트리 업데이트가 메인 스레드 점유
- 우선순위 개념 없음
- 한 번 시작한 렌더는 끝까지
- Suspense / Concurrent 같은 기능 구현 자체가 어려움
- 명시적 Fiber 트리 + 작업 큐
- 작업 단위마다 yield 가능 → 입력/애니메이션 우선
- 우선순위(Lane) 기반 스케줄링
- 중단·재시도·폐기 지원
- Concurrent / Suspense / Transitions / Streaming SSR 의 토대
"Fiber" 라는 이름의 유래
운영체제 용어인 *fiber*(스레드보다 작은 협력적 실행 단위) 에서 따왔습니다. 한 Fiber 노드는 한 컴포넌트 인스턴스에 대응하는 작업 유닛이며, React 가 다음에 무엇을 할지 결정하는 단위입니다.
핵심 통찰은 두 가지입니다. ① *작업을 쪼개라* — 한 번에 끝내지 말고 노드 단위로 처리한다. ② *작업을 데이터로 만들어라* — 콜 스택 대신 자료구조에 진행 상태를 둬야 멈췄다 다시 시작할 수 있다. 이 둘이 동시 만족되어야 우선순위·취소·재시도가 가능해집니다.
실무 적용
어떤 상황에서 사용하는가
검색창에 글자를 타이핑할 때마다 큰 결과 리스트가 다시 그려지면서 입력이 1~2 글자씩 끊긴다는 사용자 리포트가 들어왔다.
어떻게 적용하는가
(1) 입력 onChange 의 `setQuery` 는 그대로 두되, `setResults` 는 `startTransition` 으로 감싸 Transition Lane 에 보낸다. (2) 결과 영역은 `useDeferredValue(query)` 를 받아 입력보다 한 박자 늦게 갱신한다. (3) `<Suspense fallback={<Skeleton />}>` 으로 새 결과 도착 전 이전 결과를 유지한다. (4) Profiler 에서 입력 Lane 과 Transition Lane 의 commit 비율을 확인.
흔한 실수와 안티패턴
- 모든 setState 를 startTransition 으로 감싸기 — 입력처럼 즉시 보여야 할 업데이트까지 미뤄지면 오히려 끊긴다.
- Transition 안에서 `await` 후 `setState` 를 또 부르면 Transition 우선순위가 깨질 수 있음 — 한 사이클 내에서 처리.
- Strict Mode 의 이중 렌더를 회피하려고 ref 에 부수효과를 숨기는 것 — 더 깊은 버그를 만든다.
- `useLayoutEffect` 를 남용해 commit 동기 구간이 길어지면 Concurrent 의 이점을 잃는다.
흔한 오해
"Fiber 는 Virtual DOM 의 또 다른 이름이다."
교정Virtual DOM 은 개념, Fiber 는 그것을 구현하는 자료구조 + 스케줄러의 코드네임.
왜 중요같은 Virtual DOM 개념이지만 Stack Reconciler 시절에는 Fiber 가 없었다. Fiber 의 핵심은 "작업 단위로 쪼개고 멈출 수 있게 한 것".
"Render Phase 가 두 번 호출되는 건 React 18 버그다."
교정Strict Mode + Concurrent 의 의도된 동작. 부수효과 버그를 노출하기 위한 검증 장치.
왜 중요Concurrent 에서는 work-in-progress 가 실제로 폐기·재시도될 수 있어, 개발 시에도 같은 가정을 강제로 검증한다.
"useTransition 은 그냥 debounce 다."
교정debounce 는 호출 자체를 늦추지만, Transition 은 호출은 즉시 하되 *우선순위를 낮춰* React 가 양보·중단할 수 있게 한다.
왜 중요입력 도중에도 결과 계산이 시작되되, 더 급한 일이 오면 폐기되고 다시 시작한다. 결과적으로 사용자에게 "막힘" 이 사라진다.
면접 질문
답변 방향 힌트
"콜 스택 → 자료구조" 와 "작업 단위 분할" 두 축으로 답하세요.
반드시 언급할 키워드
- Stack Reconciler: 재귀, 콜 스택이 진행 상태, 중단 불가
- Fiber: 명시적 트리 + 포인터 순회 + 작업 단위로 분할
- 진행 상태가 데이터(Fiber 노드의 flags/lanes) 로 표현됨
- 단위마다 yield 가능 → 우선순위 기반 스케줄링
- 두 트리(current/wip) 의 더블 버퍼링으로 중단 안전성 확보
- 이게 Concurrent · Suspense · Streaming SSR 의 토대
예상 꼬리 질문
- Lane 모델이 expirationTime 을 대체한 이유는 무엇인가요?
- commit phase 는 왜 중단 가능하게 만들지 않았나요?
자기 점검
Fiber 노드에 두 트리가 alternate 로 존재하는 이유를 한 문장으로 답하라.
기대 키워드
자주 하는 오해
"성능 최적화" 로만 이해하면 부족하다. 두 트리는 Concurrent 에서의 *중단/재시도 안전성* 을 위한 더블 버퍼링이다.
입력 onChange 안에서 `setState` 두 개를 부르면 React 18 에서 몇 번 렌더되는가?
기대 키워드
자주 하는 오해
"두 번" 이라고 답하기 쉽지만, React 18 부터는 setTimeout/Promise/native event 어디서 호출하든 같은 tick 안의 setState 는 자동으로 묶여 한 번만 렌더된다.
Lane 모델이 expirationTime 을 대체한 이유 한 가지를 들어 보라.
기대 키워드
자주 하는 오해
"더 빠르다" 가 아니라 *표현력* 이 핵심. 단일 숫자로는 "여러 우선순위가 동시에 펜딩" 같은 상태를 표현하기 어려웠다.
학습 자료
- React Source — react-reconcilerFiber 와 Scheduler 의 실제 구현. 시간이 있다면 `ReactFiberWorkLoop.js`, `ReactFiberLane.js` 부터 읽기.Codefacebook/react
- A Cartoon Intro to Fiber — Lin Clark왜 Stack 이 안 됐는지, Fiber 의 작업 단위 모델이 왜 등장했는지를 그림으로 풀어낸 입문 강연.VideoReact Conf 2017
- Inside Fiber: in-depth overview of the new reconciliation algorithmbeginWork/completeWork 흐름, alternate 트리, effect list 까지 단계별로 코드를 따라가는 글.BlogOpenReplay (Andrey Goncharov)
- React 18 — Concurrent Featuresautomatic batching, transitions, Suspense for data 등 Fiber 기반 위에 얹힌 기능들의 공식 발표글.Docreact.dev