React’s Fiber Architecture – The Secret Behind Interruptible Rendering (And Why It’s Brilliant)

Know WHY โ€” Let AI Handle the HOW ๐Ÿค–

In Part 1, we learned how React prioritizes updates using useDeferredValue. But here’s the question that should be bugging you: How does React actually pause rendering mid-way and resume later?

What if I told you it…


This content originally appeared on DEV Community and was authored by Mohamad Msalme

Know WHY โ€” Let AI Handle the HOW ๐Ÿค–

In Part 1, we learned how React prioritizes updates using useDeferredValue. But here's the question that should be bugging you: How does React actually pause rendering mid-way and resume later?

What if I told you it's not magic - it's actually a clever data structure called Fiber that transforms your component tree into something React can pause, resume, and even throw away? Understanding this changes how you think about React performance forever.

๐Ÿค” The Problem React Had to Solve

Before we get to Fibers, let's understand the problem:

function App() {
  return (
    <div>
      <Header />
      <MainContent>
        <Article />
        <Sidebar>
          <Widget1 />
          <Widget2 />
          <Widget3 />
        </Sidebar>
      </MainContent>
      <Footer />
    </div>
  );
}

Old React (before Fiber):

  • Renders from top to bottom recursively
  • Once started, MUST finish the entire tree
  • No way to pause halfway through
  • If user clicks during render, too bad - they wait

The Challenge: How do you make rendering interruptible without breaking everything?

๐Ÿง  Think Like a Book Reader for a Moment

Imagine you're reading a book:

Without Bookmarks (Old React):

  • Start chapter 1
  • Must read straight through to the end
  • Can't stop mid-sentence
  • Can't remember where you were if interrupted

With Bookmarks (Fiber Architecture):

  • Start chapter 1
  • Can place a bookmark on any page
  • Stop reading when something urgent comes up
  • Resume exactly where you left off
  • Can even decide "this chapter isn't relevant anymore" and skip it

That's exactly what Fiber does for React rendering.

๐Ÿ”‘ What Is a Fiber? The Unit of Work

A Fiber is a JavaScript object that represents one unit of work in React. Each React element becomes a Fiber node.

// Your JSX
<DisplayCounter count={5} />

// Becomes a Fiber object (simplified):
{
  // Identity
  type: DisplayCounter,        // Component function/class
  key: null,                   // React key

  // Tree structure (linked list!)
  return: parentFiber,         // Parent (going up)
  child: firstChildFiber,      // First child (going down)
  sibling: nextSiblingFiber,   // Next sibling (going across)

  // Props and State
  pendingProps: { count: 6 },  // New props to apply
  memoizedProps: { count: 5 }, // Current props
  memoizedState: null,         // Current state

  // THE KEY TO CONCURRENT MODE!
  lanes: 0b0001,              // Priority (binary flag)
  childLanes: 0b0011,         // Children's priorities

  // Effects (what needs to happen)
  flags: Update,              // Bitwise flags

  // Double buffering
  alternate: otherVersionOfThisFiber
}

Why Linked List Instead of Array?

Array (Old React):

const tree = [
  { type: 'div', children: [
    { type: Header },
    { type: MainContent, children: [...] }
  ]}
];

// Problem: Can't easily pause mid-traversal
// Would need complex index tracking

Linked List (Fiber):

const fiber = {
  type: 'div',
  child: headerFiber,  // โ† Can pause here
};

const headerFiber = {
  type: Header,
  return: fiber,       // โ† Know where we came from
  sibling: mainFiber,  // โ† Know where to go next
};

// Can pause at any fiber and resume later!

๐Ÿ’ก The Brilliant Part: Double Buffering

React maintains TWO complete fiber trees at all times:

  1. Current Tree - What's displayed on screen right now
  2. Work-in-Progress Tree - What React is building
// Current tree (what user sees)
const currentTree = {
  type: App,
  child: {
    type: 'div',
    child: {
      type: DisplayCounter,
      props: { count: 5 },
      alternate: wipFiber  // โ† Points to work-in-progress version
    }
  }
};

// Work-in-progress tree (what React is building)
const workInProgressTree = {
  type: App,
  child: {
    type: 'div',
    child: {
      type: DisplayCounter,
      props: { count: 6 },  // โ† New count!
      alternate: currentFiber  // โ† Points back to current
    }
  }
};

Why This Is Genius:

// React can work on work-in-progress tree
// User still sees current tree (stable UI)

// If interrupted by urgent update:
// โ†’ Just throw away work-in-progress tree
// โ†’ Start fresh with new priorities
// โ†’ No harm done!

// When rendering completes:
// โ†’ Swap pointers in ONE atomic operation
// โ†’ current = workInProgress
// โ†’ workInProgress = current

Real Example: Updating a Counter

function App() {
  const [count, setCount] = useState(5);
  const deferredCount = useDeferredValue(count);

  return (
    <div>
      <DisplayCounter count={count} />         {/* Fiber A */}
      <ExpensiveList count={deferredCount} />  {/* Fiber B */}
    </div>
  );
}

After user clicks (count becomes 6):

// CURRENT TREE (still visible on screen)
Fiber A: {
  type: DisplayCounter,
  props: { count: 5 },  // Old value
  lanes: 0b0000,
}

Fiber B: {
  type: ExpensiveList,
  props: { count: 5 },  // Old value
  lanes: 0b0000,
}

// WORK-IN-PROGRESS TREE (being built)
Fiber A (WIP): {
  type: DisplayCounter,
  props: { count: 6 },     // New value!
  lanes: 0b0001,           // SyncLane - HIGH PRIORITY
  alternate: currentFiberA // Points to current tree
}

Fiber B (WIP): {
  type: ExpensiveList,
  props: { count: 5 },     // Still old (deferred!)
  lanes: 0b1000,           // TransitionLane - LOW PRIORITY
  alternate: currentFiberB
}

๐ŸŽฏ Priority Lanes: How React Tracks Urgency

React uses binary flags for lightning-fast priority checks.

// Priority lanes (actual React source - simplified)
const SyncLane            = 0b0000000000000000000000000000001; // Highest
const InputContinuousLane = 0b0000000000000000000000000000100;
const DefaultLane         = 0b0000000000000000000000000010000;
const TransitionLane      = 0b0000000000000000000001000000000; // Low priority
const IdleLane            = 0b0100000000000000000000000000000; // Lowest

// Why binary? Super fast operations:
const hasUrgentWork = (lanes & SyncLane) !== 0;  // Single CPU instruction!
const combinedWork = lanes1 | lanes2;            // Merge priorities instantly

How useDeferredValue Sets Lanes

function App() {
  const [count, setCount] = useState(0);
  const deferredCount = useDeferredValue(count);

  // When count updates:
  // 1. Components using `count` get SyncLane (0b0001)
  // 2. Components using `deferredCount` get TransitionLane (0b1000)
}

Internal priority assignment:

// Simplified React internals
function scheduleUpdate(fiber, newValue, isDeferred) {
  if (isDeferred) {
    // LOW PRIORITY - can be interrupted
    fiber.lanes = TransitionLane;
    fiber.pendingProps = newValue;
  } else {
    // HIGH PRIORITY - process immediately
    fiber.lanes = SyncLane;
    fiber.pendingProps = newValue;
  }

  // Bubble priority up to root
  let parent = fiber.return;
  while (parent) {
    parent.childLanes |= fiber.lanes;  // Bitwise OR combines lanes
    parent = parent.return;
  }
}

๐Ÿ”„ The Two Phases of Rendering

React's work is split into two distinct phases:

Phase 1: Render Phase (Interruptible โœ…)

This is where React can pause.

function workLoopConcurrent() {
  // THE KEY: This loop can be interrupted!
  while (workInProgress !== null && !shouldYield()) {
    performUnitOfWork(workInProgress);
  }

  // If shouldYield() returns true, we pause here
  // workInProgress remembers where we stopped
  // We can resume later from this exact fiber!
}

function performUnitOfWork(fiber) {
  // Step 1: Call the component
  const children = fiber.type(fiber.props);

  // Step 2: Reconcile (diff) children
  reconcileChildren(fiber, children);

  // Step 3: Return next unit of work
  if (fiber.child) return fiber.child;      // Go down
  if (fiber.sibling) return fiber.sibling;  // Go across
  return fiber.return;                      // Go up
}

Example: Rendering Pauses Mid-Tree

<App>
  <Header />              {/* โœ… Rendered */}
  <MainContent>
    <Article />           {/* โœ… Rendered */}
    <Sidebar>
      <Widget1 />         {/* โœ… Rendered */}
      <Widget2 />         {/* โธ๏ธ PAUSE HERE - shouldYield() = true */}
      <Widget3 />         {/* โณ Not rendered yet */}
    </Sidebar>
  </MainContent>
  <Footer />              {/* โณ Not rendered yet */}
</App>

// React: "Used my 5ms time slice, better let browser handle user input"
// workInProgress = Widget2Fiber
// Can resume from here later!

Key Characteristics:

  • โœ… No DOM mutations yet
  • โœ… Can pause at any fiber
  • โœ… Can resume where left off
  • โœ… Can throw away all work if urgent update arrives
  • โœ… Pure computations only

Phase 2: Commit Phase (Uninterruptible โŒ)

Once render phase completes, React commits changes atomically.

function commitRoot(root) {
  const finishedWork = root.finishedWork;

  // THIS PHASE CANNOT BE INTERRUPTED!
  // Must complete to avoid inconsistent UI

  // Sub-phase 1: Before mutation
  commitBeforeMutationEffects(finishedWork);
  // โ†’ Calls getSnapshotBeforeUpdate
  // โ†’ Schedules useEffect

  // Sub-phase 2: Mutation (THE CRITICAL MOMENT)
  commitMutationEffects(finishedWork);
  // โ†’ Actual DOM updates happen here
  // โ†’ All at once, atomically

  // Sub-phase 3: Switch trees (ATOMIC SWAP)
  root.current = finishedWork;
  // โ†‘ NOW the new tree is visible!

  // Sub-phase 4: Layout effects
  commitLayoutEffects(finishedWork);
  // โ†’ Calls useLayoutEffect
  // โ†’ Calls componentDidMount/Update
}

Why Must Commit Be Uninterruptible?

// Imagine if commit could pause mid-way:
function UserProfile() {
  return (
    <div>
      <Avatar src={user.avatar} />
      <Name>{user.name}</Name>
      <Email>{user.email}</Email>
    </div>
  );
}

// If paused after Avatar but before Name/Email:
// DOM shows:
//   Avatar for User B
//   Name for User A  โ† INCONSISTENT!
//   Email for User A โ† INCONSISTENT!
// 
// Users would see mixed data! ๐Ÿ˜ฑ

๐ŸŽฏ Real-World Example: Search with Interruption

function SearchPage() {
  const [query, setQuery] = useState('');
  const deferredQuery = useDeferredValue(query);

  const results = useMemo(() => {
    // Expensive filtering
    return bigDataset.filter(item => 
      item.name.includes(deferredQuery)
    );
  }, [deferredQuery]);

  return (
    <div>
      <input value={query} onChange={e => setQuery(e.target.value)} />
      <ResultsList items={results} />
    </div>
  );
}

What happens internally when you type "react":

User types "r":
0ms:  query = "r"
1ms:  RENDER PHASE (HIGH PRIORITY)
      โ†’ Input fiber: lanes = SyncLane
      โ†’ Render <input value="r" /> โœ…
2ms:  COMMIT PHASE
      โ†’ Update DOM, input shows "r" โœ…
3ms:  RENDER PHASE (LOW PRIORITY)
      โ†’ ResultsList fiber: lanes = TransitionLane
      โ†’ Start filtering for "r"
      โ†’ ResultsList fiber #1 rendering...
      โ†’ ResultsList fiber #2 rendering...

10ms: User types "e" (NEW HIGH PRIORITY UPDATE!)
11ms: shouldYield() = true (time to check for urgent work)
12ms: React finds SyncLane work waiting
13ms: ABANDON work-in-progress tree (throw it away!)
14ms: RENDER PHASE (HIGH PRIORITY)
      โ†’ Input fiber: lanes = SyncLane
      โ†’ Render <input value="re" /> โœ…
15ms: COMMIT PHASE
      โ†’ Update DOM, input shows "re" โœ…
16ms: RENDER PHASE (LOW PRIORITY)
      โ†’ ResultsList: START NEW render for "re"
      โ†’ Old "r" filter abandoned, never committed!

The user never sees results for "r" - React intelligently skipped that intermediate state!

๐Ÿ  The Perfect Analogy: Construction Site with Blueprints

Think of React's Fiber system like a construction site:

Current Tree = The actual building people are using
Work-in-Progress Tree = Blueprint and temporary scaffolding

  • Workers can modify the blueprint/scaffolding all day
  • People in the building don't see any changes (stable!)
  • If plans change, just throw away the scaffolding
  • When blueprint is done, do the final construction (commit phase)
  • Switch happens all at once - no half-renovated rooms

๐Ÿง  The Mental Model Shift

Stop Thinking:

  • "React renders top to bottom"
  • "Once rendering starts, it must finish"
  • "State updates are immediate"

Start Thinking:

  • "React renders fiber by fiber (unit by unit)"
  • "React can pause between any two fibers"
  • "React builds a new tree in the background"
  • "Priorities determine which fibers render first"
  • "Only commit phase makes changes visible"

๐Ÿ’ญ The Takeaway

Many developers learn the HOW: "Use React hooks and it works."

When you understand the WHY: "React uses Fiber nodes in a linked list structure with priority lanes, enabling interruptible rendering through double buffering," you gain insights that help you:

  • Understand why some updates feel instant and others don't
  • Know when to use useDeferredValue vs useTransition
  • Debug performance issues by thinking about fiber priorities
  • Make better architectural decisions


This content originally appeared on DEV Community and was authored by Mohamad Msalme


Print Share Comment Cite Upload Translate Updates
APA

Mohamad Msalme | Sciencx (2025-09-30T21:39:42+00:00) React’s Fiber Architecture – The Secret Behind Interruptible Rendering (And Why It’s Brilliant). Retrieved from https://www.scien.cx/2025/09/30/reacts-fiber-architecture-the-secret-behind-interruptible-rendering-and-why-its-brilliant/

MLA
" » React’s Fiber Architecture – The Secret Behind Interruptible Rendering (And Why It’s Brilliant)." Mohamad Msalme | Sciencx - Tuesday September 30, 2025, https://www.scien.cx/2025/09/30/reacts-fiber-architecture-the-secret-behind-interruptible-rendering-and-why-its-brilliant/
HARVARD
Mohamad Msalme | Sciencx Tuesday September 30, 2025 » React’s Fiber Architecture – The Secret Behind Interruptible Rendering (And Why It’s Brilliant)., viewed ,<https://www.scien.cx/2025/09/30/reacts-fiber-architecture-the-secret-behind-interruptible-rendering-and-why-its-brilliant/>
VANCOUVER
Mohamad Msalme | Sciencx - » React’s Fiber Architecture – The Secret Behind Interruptible Rendering (And Why It’s Brilliant). [Internet]. [Accessed ]. Available from: https://www.scien.cx/2025/09/30/reacts-fiber-architecture-the-secret-behind-interruptible-rendering-and-why-its-brilliant/
CHICAGO
" » React’s Fiber Architecture – The Secret Behind Interruptible Rendering (And Why It’s Brilliant)." Mohamad Msalme | Sciencx - Accessed . https://www.scien.cx/2025/09/30/reacts-fiber-architecture-the-secret-behind-interruptible-rendering-and-why-its-brilliant/
IEEE
" » React’s Fiber Architecture – The Secret Behind Interruptible Rendering (And Why It’s Brilliant)." Mohamad Msalme | Sciencx [Online]. Available: https://www.scien.cx/2025/09/30/reacts-fiber-architecture-the-secret-behind-interruptible-rendering-and-why-its-brilliant/. [Accessed: ]
rf:citation
» React’s Fiber Architecture – The Secret Behind Interruptible Rendering (And Why It’s Brilliant) | Mohamad Msalme | Sciencx | https://www.scien.cx/2025/09/30/reacts-fiber-architecture-the-secret-behind-interruptible-rendering-and-why-its-brilliant/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.