Fiber Architecture & Rendering Pipeline

📖 Concept

React Fiber is the complete rewrite of React's core algorithm (React 16+). It replaced the old synchronous, recursive reconciler with an incremental, interruptible rendering engine.

Why Fiber was created: The old reconciler (Stack) processed the entire component tree synchronously. For a tree with 10,000 nodes, rendering was a single blocking operation — the JS thread couldn't handle user input or animations until done. On mobile, this caused dropped frames and unresponsive UIs.

Fiber's key innovation — work can be:

  1. Paused — Stop rendering mid-tree to handle urgent work
  2. Resumed — Continue where it left off
  3. Abandoned — Discard incomplete work if priorities changed
  4. Reused — Skip unchanged subtrees

Fiber node structure (each component becomes a Fiber):

FiberNode {
  type: ComponentType,     // Function, Class, or host ('View', 'Text')
  key: string | null,
  child: Fiber | null,     // First child
  sibling: Fiber | null,   // Next sibling
  return: Fiber | null,    // Parent
  stateNode: Instance,     // DOM node / Native view / Class instance
  memoizedState: any,      // Hooks linked list (for function components)
  memoizedProps: Props,     // Last rendered props
  pendingProps: Props,      // Incoming props (not yet committed)
  effectTag: number,       // What needs to happen (placement, update, deletion)
  alternate: Fiber | null, // Double buffering — current ↔ work-in-progress
}

Two-phase rendering:

Phase 1: Render (Interruptible)

  • Traverses the Fiber tree (depth-first)
  • Calls component functions / render methods
  • Computes diffs (what changed)
  • Builds a list of "effects" (side effects to apply)
  • CAN be interrupted and restarted

Phase 2: Commit (Synchronous, Not interruptible)

  • Applies all effects to the native view hierarchy
  • Runs useLayoutEffect callbacks (synchronous)
  • Schedules useEffect callbacks (asynchronous)
  • CANNOT be interrupted — ensures UI consistency

Priority levels (Lanes model in React 18+):

Priority Examples Interruptibility
Sync User input, focus Cannot be interrupted
Discrete Click events High priority
Continuous Scroll, hover Can be interrupted by discrete
Default Data fetching results Can be interrupted
Transition startTransition Lowest — can be abandoned
Idle Prefetching, analytics Only when nothing else to do

💻 Code Example

codeTap to expand ⛶
1// === FIBER IN PRACTICE ===
2
3// Understanding how Fiber processes this tree:
4function App() {
5 return (
6 <View> {/* Fiber 1: child→Fiber2, sibling→null */}
7 <Header /> {/* Fiber 2: child→null, sibling→Fiber3 */}
8 <Content> {/* Fiber 3: child→Fiber4, sibling→Fiber5 */}
9 <Article /> {/* Fiber 4: child→null, sibling→null */}
10 </Content>
11 <Footer /> {/* Fiber 5: child→null, sibling→null */}
12 </View>
13 );
14}
15
16// Traversal order (depth-first):
17// 1. View → 2. Header → 3. Content → 4. Article →
18// (back up) 5. Footer → (back up to View, done)
19
20// Each step is a "unit of work" that CAN be interrupted between steps
21
22// === DOUBLE BUFFERING (current vs work-in-progress) ===
23
24// React maintains TWO fiber trees:
25// - current: what's on screen right now
26// - workInProgress: what we're building for the next update
27
28// After commit, workInProgress BECOMES current
29// This enables:
30// 1. Comparing old vs new (diffing)
31// 2. Abandoning incomplete work without affecting displayed UI
32// 3. Reusing unchanged fibers (structural sharing)
33
34// === PRACTICAL IMPLICATIONS FOR RN PERFORMANCE ===
35
36// 1. startTransition — mark updates as non-urgent
37import { startTransition, useState } from 'react';
38
39function SearchScreen() {
40 const [query, setQuery] = useState('');
41 const [results, setResults] = useState([]);
42
43 const handleSearch = (text: string) => {
44 // This is urgent — update input immediately
45 setQuery(text);
46
47 // This is NOT urgent — can be interrupted by typing
48 startTransition(() => {
49 const filtered = expensiveFilter(allItems, text);
50 setResults(filtered);
51 });
52 };
53
54 return (
55 <>
56 <TextInput value={query} onChangeText={handleSearch} />
57 {/* Results render with lower priority — typing stays responsive */}
58 <FlatList data={results} renderItem={renderItem} />
59 </>
60 );
61}
62
63// 2. useDeferredValue — defer costly re-renders
64import { useDeferredValue } from 'react';
65
66function SearchResults({ query }: { query: string }) {
67 // deferredQuery updates with lower priority
68 const deferredQuery = useDeferredValue(query);
69 const isStale = query !== deferredQuery;
70
71 // Expensive computation uses deferred value
72 const results = useMemo(
73 () => filterItems(allItems, deferredQuery),
74 [deferredQuery]
75 );
76
77 return (
78 <View style={{ opacity: isStale ? 0.7 : 1 }}>
79 <FlatList data={results} renderItem={renderItem} />
80 </View>
81 );
82}
83
84// 3. Understanding effect timing in Fiber
85function EffectTimingDemo() {
86 useEffect(() => {
87 // Runs AFTER commit, asynchronously
88 // Safe for: data fetching, subscriptions, analytics
89 console.log('useEffect — async after paint');
90 });
91
92 useLayoutEffect(() => {
93 // Runs AFTER commit, SYNCHRONOUSLY, BEFORE browser paint
94 // Use for: measuring layout, synchronous DOM updates
95 // ⚠️ Blocks painting — keep it fast!
96 console.log('useLayoutEffect — sync before paint');
97 });
98
99 // Execution order:
100 // 1. Render phase: component function runs
101 // 2. Commit phase: DOM/native updates applied
102 // 3. useLayoutEffect fires (sync, before paint)
103 // 4. Browser paints
104 // 5. useEffect fires (async, after paint)
105}

🏋️ Practice Exercise

Fiber Architecture Exercises:

  1. Draw the Fiber tree (child/sibling/return pointers) for a component with 3 levels of nesting
  2. Use React DevTools Profiler to visualize which fibers are "committed" vs "bailed out" during a state update
  3. Implement a search input that uses startTransition to keep typing responsive while filtering 10K items
  4. Compare the performance of useEffect vs useLayoutEffect for measuring component dimensions
  5. Create a demo showing how Fiber interrupts low-priority work when high-priority input arrives

⚠️ Common Mistakes

  • Putting expensive computations in the render function — they run in the render phase which may execute multiple times in concurrent mode

  • Using useLayoutEffect for async operations — it blocks painting and should only be used for synchronous layout measurements

  • Not understanding that render phase is NOT the same as commit phase — side effects in render can execute multiple times or never

  • Assuming startTransition makes things faster — it prioritizes responsiveness over throughput, the work still needs to be done

  • Not considering that React may call your component function multiple times during concurrent rendering — side effects MUST be in effects, not in the render body

💼 Interview Questions

🎤 Mock Interview

Mock interview is powered by AI for Fiber Architecture & Rendering Pipeline. Login to unlock this feature.