Skip to main content

React Fiber Architecture

Answer

React Fiber is the reimplementation of React's core algorithm introduced in React 16. It enables incremental rendering, allowing React to split rendering work into chunks and spread it out over multiple frames.

Why Fiber Was Needed

Fiber Node Structure

// Simplified Fiber node
{
type: ComponentType, // Function/Class component or 'div', 'span'
key: null | string,
props: { children, ... },
stateNode: DOM | Component, // Reference to actual instance

// Fiber links (linked list tree)
return: Fiber | null, // Parent fiber
child: Fiber | null, // First child fiber
sibling: Fiber | null, // Next sibling fiber

// Work tracking
pendingProps: Props,
memoizedProps: Props,
memoizedState: State,

// Effects
effectTag: number, // What needs to be done (placement, update, delete)
nextEffect: Fiber | null, // Next fiber with side effects
}

Two Phase Rendering

Priority Levels

// React's scheduling priorities (simplified)
const priorities = {
ImmediatePriority: 1, // User typing, clicking
UserBlockingPriority: 2, // Hover, scroll
NormalPriority: 3, // Data fetching, transitions
LowPriority: 4, // Analytics
IdlePriority: 5, // Pre-rendering off-screen content
};

// Higher priority work can interrupt lower priority work

Concurrent Features

// useTransition - mark updates as non-urgent
function Search() {
const [query, setQuery] = useState("");
const [results, setResults] = useState([]);
const [isPending, startTransition] = useTransition();

const handleChange = (e) => {
// Urgent: update input immediately
setQuery(e.target.value);

// Non-urgent: can be interrupted
startTransition(() => {
setResults(searchItems(e.target.value));
});
};

return (
<>
<input value={query} onChange={handleChange} />
{isPending && <Spinner />}
<Results items={results} />
</>
);
}

// useDeferredValue - defer updating a value
function List({ input }) {
const deferredInput = useDeferredValue(input);

// deferredInput updates after more urgent work
return <ExpensiveList filter={deferredInput} />;
}

Suspense and Fiber

// Suspense works because Fiber can pause and resume
function App() {
return (
<Suspense fallback={<Loading />}>
<AsyncComponent />
</Suspense>
);
}

// During async data fetch:
// 1. Component "suspends" (throws promise)
// 2. Fiber catches it, shows fallback
// 3. When promise resolves, resumes rendering
// 4. Shows actual component

Work Loop

// Simplified work loop concept
function workLoop(deadline) {
let shouldYield = false;

while (nextUnitOfWork && !shouldYield) {
nextUnitOfWork = performUnitOfWork(nextUnitOfWork);

// Check if browser needs to handle other work
shouldYield = deadline.timeRemaining() < 1;
}

if (!nextUnitOfWork && wipRoot) {
// All work done, commit to DOM
commitRoot();
}

// Schedule next chunk
requestIdleCallback(workLoop);
}

Fiber Benefits

FeatureStack ReconcilerFiber
InterruptionNoYes
PriorityNoYes
ConcurrentNoYes
SuspenseNoYes
Error boundariesLimitedFull
Time slicingNoYes

Double Buffering

// React maintains two fiber trees:
// 1. current - represents what's on screen
// 2. workInProgress - being built/updated

// On commit, workInProgress becomes current
// Old current becomes workInProgress for next update
// This "double buffering" avoids visual inconsistencies

Effects in Fiber

// Effects are processed in order:
// 1. Mutation effects (DOM changes)
// 2. Layout effects (useLayoutEffect)
// 3. Passive effects (useEffect)

// This ensures DOM is updated before layout effects
// and layout is stable before passive effects

Key Points

  • Fiber is React's reconciliation engine since v16
  • Enables incremental, interruptible rendering
  • Uses linked list structure for traversal
  • Two phases: Render (interruptible) + Commit (sync)
  • Work is prioritized (user input > data fetch)
  • Powers Suspense, concurrent features, time slicing
  • Double buffering prevents visual glitches