React Fiber Explained Simply: What Really Happens During Reconciliation

Introduction

In the previous article, we looked at a real bug caused by non-unique keys and how React's reconciliation logic reused the wrong components. This follow-up dives deeper into the engine that makes reconciliation possible: React Fiber.

If you've ever wondered what actually happens between a setState() call and a visible DOM change, this one's for you.

What Is React Fiber?

React Fiber is the internal architecture that powers React's rendering and scheduling since React 16. Before Fiber, React used a stack-based reconciler that processed the component tree synchronously from top to bottom. Long renders could block the main thread and freeze the UI.

Fiber replaced that with a linked-list tree of "fibers" - tiny units of work that React can start, pause, and resume. This allows features like concurrent rendering, suspense, and fine-grained prioritisation.

The Three Major Phases

1. Scheduling

When state or props change, React calls:

scheduleUpdateOnFiber(fiber);

This marks the affected fiber (and its ancestors) as dirty and schedules a render for that root. React may decide to run it synchronously or concurrently depending on priority and available time.

2. Render Phase (Reconciliation)

This is the "diff" step. React builds the next tree of fibers and decides what needs to change in the real DOM.

Important functions:

  • performUnitOfWork - processes one fiber
  • beginWork - compares the current fiber's children to new elements
  • completeWork - finalises the fiber and prepares effect flags

Important: No DOM changes occur here. This phase can be paused, resumed, or even abandoned mid-way.

3. Commit Phase

Once the new fiber tree is complete, React performs the actual DOM work. This phase is synchronous and non-interruptible.

It runs in three steps:

1. Before-mutation phase (commitBeforeMutationEffects)

  • Runs getSnapshotBeforeUpdate and detaches old refs

2. Mutation phase (commitMutationEffects)

  • Applies DOM updates, insertions, deletions, and ref detachments

3. Layout phase (commitLayoutEffects)

  • Runs useLayoutEffect, componentDidMount/Update, and attaches refs

Finally, passive effects (useEffect) are flushed on a later tick.

Keys and Identity in the Fiber World

Every child element in React gets turned into a fiber node. To know whether a fiber should be reused or recreated, React checks:

  1. Type (component or host element)
  2. Key

If both match, React updates the existing fiber; otherwise, it destroys and recreates it. That's why stable, unique keys are so critical: they directly determine which fibers survive reconciliation.

Why Fiber Matters for Developers

Understanding Fiber helps you reason about:

  • Why effects run twice in Strict Mode - React deliberately mounts, unmounts, and remounts to catch side-effects that aren't idempotent
  • Why some renders feel "paused" - In concurrent mode, React may yield between beginWork calls
  • Why refs aren't updated during render - They're written in the layout step of the commit phase, after the new DOM is ready
  • Why bad keys cause stale content - Reusing the same key makes Fiber reuse the same subtree and its DOM nodes

Visual Summary

The React Fiber rendering pipeline follows this flow:

1. Trigger

setState() - A state update is triggered

2. Schedule

scheduleUpdateOnFiber - React schedules the update based on priority

3. Render Phase (Interruptible)

  • beginWork - Start processing fibers
  • completeWork - Finalize fiber work
  • Diff the virtual tree to determine changes
  • No DOM mutations yet

4. Commit Phase (Synchronous)

  • Apply all DOM changes (insertions, updates, deletions)
  • Run layout effects (useLayoutEffect)
  • Attach refs
  • Schedule passive effects (useEffect) for later

Practical Takeaways

  1. Keep keys stable and meaningful
  2. Don't read refs during render - They're only valid after commit
  3. Use useLayoutEffect for measurements - After DOM writes, before paint
  4. Avoid heavy synchronous renders - React can't yield during commit
  5. Remember: React never "guesses" - If keys or types match, it reuses - otherwise it rebuilds

Further Reading

Conclusion

React Fiber isn't just an implementation detail - it's what enables everything from concurrent rendering to smooth UI updates. Once you understand how it slices rendering into units of work and commits in phases, seemingly "random" React behaviours start to make perfect sense.

In short: React Fiber is the reason your UI stays responsive. Give it the right signals (unique keys, clean effects, and predictable mutations), and it'll take care of the rest.