O(n³)에서 O(n)으로, React가 DOM을 다루는 방식
React의 핵심 원리와 Fiber 아키텍처
React의 핵심은 DOM을 효율적으로 갱신하는 것에 있습니다.
브라우저의 실제 DOM(Document Object Model)은 조작 비용이 매우 크기 때문에, React는 이를 직접 다루지 않고 가상 DOM(Virtual DOM) 을 통해 변경 사항을 관리합니다.
React는 이전 렌더링 결과와 새로운 렌더링 결과를 트리 구조로 비교(diffing) 하여, 변경된 부분만 실제 DOM에 반영합니다. 이 과정 덕분에 화면의 깜박임 없이 자연스러운 UI 업데이트가 가능해집니다.
트리 비교 알고리즘의 복잡도와 React의 접근 방식
일반적으로 두 트리의 차이를 찾는 알고리즘의 시간 복잡도는 O(n³) 수준입니다.
이 방식으로는 렌더링할 때마다 막대한 연산이 필요하므로, 실제 애플리케이션 환경에서는 비효율적입니다.
React는 이러한 문제를 해결하기 위해 휴리스틱(Heuristic) 규칙을 적용하여, 트리 비교의 시간 복잡도를 O(n) 으로 줄였습니다.
이때 적용되는 대표적인 규칙은 다음 두 가지입니다.
- 노드 타입이 바뀌면 하위 트리를 모두 교체합니다.
예를 들어<div>가<span>으로 변경된다면, 해당 노드 하위의 모든 자식 요소가 새로 생성됩니다. keyprop을 활용하여 동일한 요소를 추적합니다.
리스트 렌더링 시 각 항목에 고유한key를 부여하면, React는 이전 렌더 결과와 새로운 결과를 비교할 때 동일한 항목으로 인식하여 불필요한 재렌더링을 방지합니다.
이 두 가지 단순하지만 강력한 규칙 덕분에 React는 대부분의 UI에서 빠르고 효율적인 업데이트를 수행할 수 있습니다.
개인적으로 가장중요한 부분이라고 생각됩니다. 이러한 접근방식이 없었다면 지금의 SPA는 태어나지 않았을수도 있습니다. 나머지는 문제 해결이니까요.
Call Stack 기반 렌더링의 한계
초기의 React는 재귀 호출 기반의 트리 순회 방식을 사용했습니다.
컴포넌트 트리를 재귀적으로 탐색하면서 한 번에 전체 렌더링을 수행하는 구조였죠.
하지만 애플리케이션이 커질수록 렌더링 작업이 길어지고, 그 동안 메인 스레드가 차단(blocked) 되는 문제가 발생했습니다.
이로 인해 사용자는 애플리케이션이 잠시 멈춘 듯한 지연 을 체감하게 되었습니다.

이 문제를 해결하기 위해 콜스택의 사용을 줄이고 힙메모리를 주로 사용하는 방향으로 설계를 변경하게 됩니다.
Fiber: React의 새로운 렌더링 엔진
React 팀은 렌더링 구조를 전면적으로 개편하였고, 그 결과 탄생한 것이 바로 Fiber 아키텍처입니다.
Fiber는 각 컴포넌트를 하나의 작업 단위(Unit of Work) 로 관리하는 연결 리스트(Linked List) 형태의 자료구조입니다.
이 구조를 통해 React는 렌더링 작업을 일시 중단(pause) 했다가 재개(resume) 할 수 있게 되었습니다.
주요 특징은 다음과 같습니다.
- 작업 단위 분할 (Incremental Rendering)
렌더링을 작은 단위의 Fiber로 나누어 처리하며, 일정 시간(Deadline)을 초과하면 브라우저에게 제어권을 돌려줍니다.
이후 여유 시간이 생기면 중단된 작업부터 다시 이어서 수행합니다. - 더블 버퍼링(Double Buffering)
React는 화면에 표시 중인 Fiber 트리와 작업 중인 Fiber 트리를 별도로 유지합니다.
작업이 완료되면 두 트리를 교체하여, 렌더링 중에도 UI의 안정성을 보장합니다. - 비재귀적 트리 순회
기존의 재귀 호출 대신while문 기반의 fiber 노드의 순회를 통해,
렌더링 중에도 스케줄링과 중단이 자유로운 구조를 구현했습니다.

Concurrent Rendering: 동시성을 위한 진화
Fiber 아키텍처의 등장은 React가 동시성 렌더링(Concurrent Rendering) 으로 나아갈 수 있는 기반이 되었습니다.
동시성 렌더링은 "여러 렌더링 작업을 동시에 처리한다"는 뜻이 아니라,
사용자 상호작용을 우선순위에 따라 지능적으로 스케줄링하는 렌더링 방식을 의미합니다.
예를 들어 사용자가 입력 중인 텍스트 입력창과, 백그라운드에서 실행되는 무거운 렌더링 작업이 있다고 가정해 보겠습니다.
기존 구조에서는 긴 렌더링 작업 때문에 입력 반응이 느려질 수 있었지만,
Concurrent 모드에서는 React가 두 작업의 우선순위(priority) 를 판단하여,
먼저 사용자 입력을 처리한 뒤 나머지 렌더링을 이어갑니다.
이 동작은 스케줄러(Scheduler) 와 Fiber의 비동기적 구조가 결합되어 가능해졌습니다.
이를 통해 React는 다음과 같은 효과를 얻습니다.
- 긴 렌더링 중에도 사용자 입력에 즉각 반응
- 불필요한 렌더링을 중단하고 최신 상태만 반영
- 애니메이션이나 전환 효과의 프레임 손실 최소화
이러한 개념은 React 18에서 도입된 Concurrent Features (예: useTransition)와 함께 본격적으로 구현되었습니다.
즉, React는 단순한 UI 라이브러리가 아니라 스케줄링이 가능한 UI 엔진으로 진화한 것입니다.
마무리
React의 발전은 단순히 렌더링 속도를 높이는 수준을 넘어,
사용자 경험을 우선시하는 아키텍처적 혁신으로 이어졌습니다.
가상 DOM을 통한 최소 변경, Fiber 아키텍처를 통한 작업 단위화,
그리고 Concurrent Rendering을 통한 우선순위 기반 스케줄링까지.
이 모든 요소가 결합되어 React는 오늘날처럼 대규모 애플리케이션에서도 부드럽고 즉각적인 인터랙션을 제공할 수 있게 되었습니다.
Member discussion