본문으로 건너뛰기
KYH
  • Blog
  • About

joseph0926

I document what I learn while solving product problems with React and TypeScript.

HomeBlogAbout

© 2026 joseph0926. All rights reserved.

react

React: React Fiber

Let’s explore Fiber, introduced starting with React v16.

Jun 25, 20256 min read
React: React Fiber

React Fiber Architecture

React’s Internal Mechanism Before Fiber

React previously used a mechanism called the Stack Reconciler. Put simply, it detects changes through recursion and applies updates all at once. This approach is very intuitive, but it had a few problems.

Frame Drops During Large-Scale Updates

If we describe React v15’s approach in a bit more detail, it largely proceeds in two phases.

  1. Render phase: a pure, function-like section that only computes what to change - e.g., render
  2. Commit phase: applies the computed result to the actual DOM/Refs/Effects while triggering side effects - e.g., componentDidMount

In other words, step 1 computes what should be reflected in the DOM -> step 2 actually applies it and runs side effects.

The biggest issue with this approach is that the entire sequence runs synchronously. React is ultimately a JavaScript library, which means it runs on a single thread. With that in mind, an approach that updates all changes at once is bound to run into problems. Because applying updates—reflecting UI changes—means occupying the call stack. And if that work is large, it also means other tasks are blocked during that time.

Quantitatively, browsers are generally said to need to process an update within 60fps (about 16.7ms) for users to perceive it as smooth and uninterrupted.

Reference: dev.to

But if the work is so large that it exceeds this budget, users experience a kind of stutter (janky) behavior.

Also, because this mechanism did not support priority updates—which later became central to Concurrent Mode—more important updates could not be processed first. For example, important updates that require immediate feedback, like user input, could be blocked.

Start user input
|
v
Initiating a large DOM update
|
v
User input is blocked until the large DOM update is complete.
rAF ticker: 0
버튼을 누르는 순간 애니메이션·타이핑·ticker가 3초간 멈추는 현상을 확인하세요.

Introducing Fiber

The React team was also aware of how serious these issues were, and to solve them and build a better React, they introduced a new reconciler starting with v16. The core goals the React team set were as follows:

Reference: React member GitHub

  • Process work according to appropriate priorities (run urgent work such as animations first)

    • For priority comparison, React uses the Lanes model rather than simple numeric comparison.

      • A bitmask that represents priority in 1-bit units
    • Thanks to the bitmask, multiple priorities can be preserved simultaneously within a single integer.

    • Even if there are many pending updates, React can determine the highest-priority work to run now in constant time.

  • Pause work and resume it later (to avoid exceeding the browser’s frame budget)

  • Abort/cancel work that is no longer needed

  • Reuse previously completed work results (to reduce unnecessary computation)

The core of Fiber is splitting render work into small units of work and delegating each unit to a Lanes-based scheduler to avoid blocking the main thread. By slicing work into multiple pieces and yielding control back to the browser between units, React approaches solving the issues above.

More specifically, instead of traversing the entire tree all the way down in one go, Fiber repeats a process of going down in small steps and then coming back up while performing work. When I first read this sentence, I had two questions.

  1. If it repeatedly goes down and up, wouldn’t that be slower than running recursion all at once?
  2. Then wouldn’t it exceed 16ms anyway?

To understand this better, you need to know exactly what “going down” and “coming back up” mean.

  • Going down (begin phase)

    • This literally means starting at the top of the component tree and moving downward, doing work one component at a time.
  • Coming back up (complete phase)

    • After finishing one unit of work, instead of immediately continuing to the next, React briefly pauses to evaluate the current state—checking whether there is “enough time remaining” or whether there is “more urgent work” to handle first.

An everyday analogy is like cleaning a house: instead of cleaning the whole house in one go, you clean one room at a time, pausing to check if a guest has arrived, or if an urgent phone call comes in, you handle that first.

In summary, it’s not just reading a unit by going down and then up—it reads while going down, and once that work is done, it considers whether it should proceed to the next unit (whether enough time remains, whether there is higher-priority work, etc.). This way, rather than continuously occupying the main thread by immediately running the next unit, React yields control back to the browser in between. That allows the browser to handle interactions or higher-priority work first, improving perceived performance for users.

So we can answer question 1 like this:

  1. Total time may increase (very slightly..?), but perceived time (responsiveness) improves.
  2. The work may not complete within 16ms. However, as mentioned earlier, because the work is split into very small units, even if the entire work does not finish within 16ms, it can still transition smoothly rather than causing jank.

Taking a Closer Look at Fiber

Summarizing the above, Fiber operates based on two core ideas:

  1. Split a single task into small units of work
  2. With priorities, urgent (important) units are processed first

In this section, we’ll take a closer look at how Fiber is structured and how it operates.

A fiber node (one unit of work) is implemented as a JavaScript object and contains information about a specific component (or DOM element). Fiber nodes form a tree in the shape of a linked list, expressing parent-child and sibling relationships via pointers such as child, sibling, and return. Thanks to this structure, React can traverse the tree using iteration or traversal algorithms instead of recursion, and it can pause or resume work at the necessary times.

A fiber node is structured as follows.

FieldTypeRole / Notes
typeFunction | string

Component function/class or host tag like "div"

keystring | nullUnique sibling identifier during list diff

child / sibling / return

Fiber | null

DFS traversal pointers:
- child: descend (begin)
- sibling: move across same level
- return: ascend to parent (complete)

lanes

Lanes (bitmask)

Priority bits assigned to this node
childLanesLanes

OR'ed lanes of subtree for O(1) skip checks

flags / subtreeFlags

SideEffectFlagsSide effects to run in commit phase

memoizedProps / memoizedState

anyCache of previous render result
pendingPropsanyNew props for current render
alternateFiber | null

Double buffering structure:


Current tree <-> Work-In-Progress tree

참고 React 18부터 기존 pendingWorkPriority 숫자 필드는 사라지고, lanes·childLanes 비트마스크가 모든 우선순위 정보를 담습니다.

Below is a very simple visualization of Fiber’s mechanism.

Fiber 시각화

ImmediateApp
UserBlockingLayout
ImmediateNavbar
NormalSidebar
LowFooter
NormalContent
UserBlockingWidget
NormalReports

In summary, the React Fiber architecture is a crucial improvement introduced by React to enhance user experience and optimize performance. In particular, Fiber splits work into small pieces and assigns priorities so that urgent work can be processed first. It also minimizes frame drops even when handling long tasks, providing a smoother UI.