PROJECT 02 · INDIVIDUAL EXTENSION

Vanilla JS React Runtime

Virtual DOM과 Hooks를 직접 구현한 뒤, 동기식 Diff 구조를 작업 단위 기반의 Fiber Reconciler로 확장했습니다.

포트폴리오로 돌아가기
핵심 역할
Fiber Reconciler · Runtime 설계
실행 환경
Vanilla JavaScript · DOM
검증
83 tests passed
핵심 구조
Virtual DOM · Diff & Patch → Fiber
01

왜 직접 만들었나

React를 사용하는 것만으로는 상태 변화가 어떤 경로를 거쳐 화면 변경으로 이어지는지 정확히 설명하기 어렵다고 판단했습니다. 먼저 이전 VDOM과 다음 VDOM을 비교해 필요한 DOM 변경만 계산하는 Diff/Patch 엔진을 만들었습니다.

구현 과정에서 Virtual DOM은 무조건 빠른 기술이 아니라, 메모리상의 비교를 통해 Layout·Paint로 이어질 수 있는 실제 DOM 변경을 줄이는 전략이라는 점을 확인했습니다.

상태가 바뀌어도 현재 화면은 유지하고, 작업 중인 Fiber 트리가 완성된 뒤에만 DOM을 변경합니다.
02

VDOM에서 Fiber로

초기 엔진은 재귀적으로 전체 트리를 한 번에 비교하고, Diff 직후 Patch를 적용하는 동기식 구조였습니다. 트리가 커질수록 메인 스레드를 오래 점유하며, 계산을 중간에 멈추거나 최신 렌더 요청으로 교체하기 어렵다는 한계가 있었습니다.

BEFORE · SYNC VDOM전체 트리를 한 번에 처리
  • 재귀 Diff
  • 중단·재개 불가
  • Diff 직후 DOM 변경
AFTER · FIBER작업을 작은 단위로 분리
  • Unit of Work 순회
  • Yield · Resume · Cancel
  • Render / Commit 분리
03

Current · WIP Fiber

각 VDOM 노드를 `parent`, `child`, `sibling`, `alternate` 연결을 가진 Fiber로 변환했습니다. 현재 화면을 나타내는 Current 트리는 유지하고, 다음 화면은 Work-in-Progress 트리에서 계산합니다.

`alternate`로 이전 Fiber와 같은 type/key의 노드를 연결해 실제 DOM을 재사용하고, 변경이 있는 Fiber에만 Effect Flag를 기록합니다.

parentchildsiblingalternate
각 Fiber는 부모·첫 자식·다음 형제·이전 트리를 가리키며, 재귀 호출 스택 없이 다음 작업을 찾습니다.
04

Render · Commit · Scheduler

기존 공개 API의 동기 동작을 유지하기 위해 `patch()`는 같은 Fiber 작업을 한 번에 완료합니다. `patchAsync()`는 `requestIdleCallback`과 timeout fallback을 이용해 렌더 작업을 여러 Slice로 나누고, 브라우저가 처리할 시간이 필요하면 제어권을 양보합니다.

새로운 비동기 렌더가 들어오면 아직 Commit하지 않은 이전 작업은 취소합니다. Work-in-Progress가 끝까지 완성된 경우에만 Placement·Update·Deletion·Move Effect를 실제 DOM에 반영합니다.

`patchAsync()`는 브라우저에 제어권을 돌려주며 Render를 이어가고, Commit은 완성된 결과를 한 번에 반영합니다.
05

Keyed Reconciliation

리스트의 key를 단순한 표시 값이 아니라 노드의 동일성을 결정하는 기준으로 사용했습니다. 같은 key와 type이면 이전 Fiber와 실제 DOM을 재사용하고, 이전 index와 다음 index를 비교해 `MOVE` Effect를 계산합니다.

같은 key와 type은 동일한 노드로 판단합니다. 순서만 바뀌면 새로 생성하지 않고 기존 DOM을 이동합니다.

상태 스케줄링과 렌더 스케줄링을 분리했습니다

Hook의 microtask batching은 여러 `setState`를 언제 하나의 업데이트로 묶을지 결정하고, Fiber scheduler는 시작된 렌더를 몇 개의 작업 Slice로 나눌지 결정합니다.

06

검증과 한계

기존 Hooks·Diff/Patch·History 테스트에 Fiber 전용 시나리오를 추가해 전체 83개의 테스트를 모두 통과했습니다.

  • Fiber의 parent/child/sibling/alternate 연결
  • Render 완료 전 실제 DOM이 변경되지 않는지 확인
  • 작업 Yield와 다음 Slice에서의 Resume
  • key 기반 MOVE와 실제 DOM 노드 재사용
  • 오래된 비동기 렌더 취소와 최신 작업 Commit
실제 React의 Lane 기반 우선순위, Preemption, Suspense, Hydration은 포함하지 않았습니다. 또한 이번 Fiber는 컴포넌트별 Fiber가 아니라 최종 Host VNode 트리를 작업 단위로 나누는 학습용 구현입니다.