Open-Source Wikis

/

React

/

Packages

/

react-reconciler

facebook/react

react-reconciler

Active contributors: acdlite, sebmarkbage, gnoff, eps1lon, sophiebits, rickhanlonii

Purpose

packages/react-reconciler/ is the largest package in the runtime and the home of React's fiber engine. Everything renderer-agnostic lives here: the work loop, the lanes priority model, all built-in hook implementations, Suspense, transitions, hydration, the commit phase, error boundaries, and the new view-transition machinery. Renderers (react-dom-bindings, react-native-renderer, react-art, etc.) plug into it by providing a host config — a struct of imperative methods named in packages/react-reconciler/src/ReactFiberConfig.js.

The package is also published independently on npm under the name react-reconciler, intended for people writing their own custom renderers. Its API is intentionally not fully stable; the README warns against it.

Directory layout

packages/react-reconciler/
├── README.md                                # 350-line "writing a custom renderer" guide
├── package.json
├── index.js
├── reflection.js                            # findHostInstancesForRefresh and friends
└── src/
    ├── ReactFiber.js                        # the Fiber struct + createFiber* helpers
    ├── ReactFiberRoot.js                    # FiberRoot (one per createRoot)
    ├── ReactFiberLane.js                    # 31-bit lane bitmask, getNextLanes, etc.
    ├── ReactFiberFlags.js                   # commit-phase flags (Placement, Update, ...)
    ├── ReactWorkTags.js                     # tags identifying fiber kinds
    ├── ReactInternalTypes.js                # central type definitions
    │
    ├── ReactFiberWorkLoop.js                # ~5,000 lines: the work loop
    ├── ReactFiberBeginWork.js               # ~4,500 lines: begin half of render
    ├── ReactFiberCompleteWork.js            # ~2,000 lines: complete half of render
    ├── ReactFiberCommitWork.js              # ~5,000 lines: walking effect lists
    ├── ReactFiberCommitEffects.js           # passive / layout effects
    ├── ReactFiberCommitHostEffects.js       # host-mutation walks
    ├── ReactFiberCommitViewTransitions.js   # view transition commit
    ├── ReactFiberApplyGesture.js            # gesture-driven view transitions
    │
    ├── ReactFiberHooks.js                   # ~4,500 lines: every built-in hook
    ├── ReactFiberClassComponent.js          # the class API code path
    ├── ReactFiberClassUpdateQueue.js        # legacy class setState queue
    ├── ReactChildFiber.js                   # children diffing (the "missing key" warner)
    │
    ├── ReactFiberThrow.js                   # how thrown values bubble
    ├── ReactFiberThenable.js                # use(promise) machinery
    ├── ReactFiberSuspenseComponent.js       # Suspense boundaries
    ├── ReactFiberSuspenseContext.js
    ├── ReactFiberHiddenContext.js
    ├── ReactFiberTransition.js              # transition lanes
    ├── ReactFiberTransitionTypes.js
    ├── ReactFiberOffscreenComponent.js      # Activity (formerly Offscreen)
    ├── ReactFiberViewTransitionComponent.js
    ├── ReactFiberTracingMarkerComponent.js
    ├── ReactFiberAsyncAction.js / ReactFiberAsyncDispatcher.js
    ├── ReactFiberCacheComponent.js          # the cache() RSC primitive
    │
    ├── ReactFiberHydrationContext.js        # client-side hydration walk
    ├── ReactFiberHydrationDiffs.js          # mismatch diffing
    ├── ReactFiberShellHydration.js          # selective hydration entry
    │
    ├── ReactFiberRootScheduler.js           # what runs when, across roots
    ├── ReactFiberConcurrentUpdates.js       # interleaved-update bookkeeping
    ├── ReactFiberDevToolsHook.js            # publishes events to react-devtools
    ├── ReactFiberPerformanceTrack.js        # Performance API marks for the Profiler
    ├── ReactFiberErrorLogger.js             # console.error formatting for caught errors
    ├── ReactFiberCallUserSpace.js           # wraps user calls (render, effects, ...)
    ├── ReactFiberHotReloading.js            # hot module replacement support
    ├── ReactFiberMutationTracking.js        # mutation tracking for React Compiler
    │
    ├── ReactFiberConfig.js                  # the host-config interface (resolved per renderer)
    ├── ReactFiberConfigWithNoMutation.js    # capability shim
    ├── ReactFiberConfigWithNoHydration.js   # capability shim
    ├── ... (more capability shims)
    ├── forks/                               # per-renderer host config wiring
    │
    ├── Scheduler.js                         # thin wrapper over the published scheduler
    ├── ReactStrictModeWarnings.js
    ├── ReactProfilerTimer.js
    ├── ReactTestSelectors.js                # findAllByType / findByText
    ├── getComponentNameFromFiber.js
    ├── clz32.js                             # count-leading-zeros polyfill
    └── __tests__/                           # the central reconciler test suite

Key abstractions

Abstraction File Description
Fiber packages/react-reconciler/src/ReactFiber.js, type in ReactInternalTypes.js Per-component-instance node in the WIP/current trees. ~30 fields including tag, key, type, stateNode, child, sibling, return, alternate, flags, lanes, memoizedState, memoizedProps, pendingProps, updateQueue, dependencies.
FiberRoot packages/react-reconciler/src/ReactFiberRoot.js One per createRoot call. Owns the current tree, pending tree, lane bitmask, error log, hydration state.
Lane / Lanes packages/react-reconciler/src/ReactFiberLane.js 31-bit priority bits. SyncLane, InputContinuousLane, DefaultLane, TransitionLane1..N, RetryLane, IdleLane, OffscreenLane, DeferredLane, GestureLane.
Work tags packages/react-reconciler/src/ReactWorkTags.js FunctionComponent, ClassComponent, HostComponent, HostText, Fragment, ContextProvider, MemoComponent, LazyComponent, SuspenseComponent, ActivityComponent, ViewTransitionComponent, ...
Effect flags packages/react-reconciler/src/ReactFiberFlags.js Placement, Update, Deletion, Hydrating, Snapshot, Passive, Layout, ContentReset, Ref, Visibility, ShouldCapture, DidCapture, Forked, ...
Host config packages/react-reconciler/src/ReactFiberConfig.js (fork-resolved) Imperative interface a renderer must implement: createInstance, appendChild, commitUpdate, prepareForCommit, getCurrentEventPriority, etc.
Hooks dispatchers packages/react-reconciler/src/ReactFiberHooks.js Six tables: HooksDispatcherOnMount, OnUpdate, OnRerender, plus dev-mode variants. Each implements every built-in hook.
act() packages/react-reconciler/src/ReactFiberAct.js The reconciler half of act — flushes work and yields to passive effects.

How it works

The work loop

graph TD
  Update[setState / dispatch / root.render] -->|scheduleUpdateOnFiber| RootScheduler[ReactFiberRootScheduler.js]
  RootScheduler -->|markRootUpdated, ensureRootIsScheduled| Scheduler[scheduler package]
  Scheduler -->|resume| WorkLoop[performWorkOnRoot]
  WorkLoop -->|render phase| BeginWork[beginWork per fiber]
  BeginWork --> CompleteWork[completeWork per fiber]
  CompleteWork -->|shouldYield?| WorkLoop
  WorkLoop -->|done with render| CommitRoot[commitRoot]
  CommitRoot -->|before-mutation| Snapshot[ClassComponent getSnapshotBeforeUpdate]
  CommitRoot -->|mutation| HostMut[appendChild / removeChild / commitUpdate]
  CommitRoot -->|layout| LayoutEff[useLayoutEffect / componentDidMount]
  CommitRoot -->|after paint| Passive[useEffect: flushPassiveEffects]

Two work loops in ReactFiberWorkLoop.js:

  • performSyncWorkOnRoot — uninterruptible. Used for synchronous lanes (default setState outside transitions).
  • performConcurrentWorkOnRoot — calls shouldYield() from the scheduler between fibers. Used for transition lanes, idle lanes, retry lanes, and anything below SyncLane.

The render phase always builds a fresh WIP tree as alternate of the current tree. The commit phase then swaps current = WIP. This is React's "double buffering" — the current tree is always consistent with what's on screen.

Lanes

packages/react-reconciler/src/ReactFiberLane.js is dense bit-twiddling. The 31 lanes are ordered by priority. Key helpers:

  • getNextLanes(root, wipLanes) — picks which lanes to render in the next pass, given what's pending on the root and what's already in flight.
  • mergeLanes, removeLanes — bitwise union/diff.
  • pickArbitraryLanelanes & -lanes, the lowest set bit. The trick that makes "highest priority lane" cheap.
  • markRootUpdated, markRootEntangled, markRootSuspended, markRootFinished — bookkeeping on the FiberRoot.

packages/react-reconciler/src/ReactEventPriorities.js maps DOM events to lanes (e.g. a click is DiscreteEventPrioritySyncLane; a scroll is ContinuousEventPriorityInputContinuousLane).

Hooks

Every built-in hook has six implementations in ReactFiberHooks.js:

Phase Description
Mount First render: allocate the hook cell, set initial state.
Update Subsequent render: read previous cell, apply pending updates from queue.
Rerender Same render re-trying after setState during render.
MountInDEV / UpdateInDEV / RerenderInDEV Dev-only variants that record HookType strings for the act warnings and DevTools.

Hooks share a small set of internal primitives:

  • mountWorkInProgressHook / updateWorkInProgressHook — allocate or step the linked list of hook cells.
  • dispatchSetStateInternal — the body of setState calls; computes the lane, marks the fiber updated, schedules.
  • enqueueUpdate — appends to the hook's update queue.
  • useThenable (in ReactFiberThenable.js) — backs use(promise) and the implicit awaits inside use(...).

Suspense

Three pieces work together:

  • ReactFiberThrow.js — handles throw thenable (suspense) and throw new Error(...) (error boundary). Walks up the tree marking ancestors with ShouldCapture.
  • ReactFiberSuspenseComponent.js and ReactFiberSuspenseContext.js — represent a Suspense boundary, decide whether to show fallback or content, suspend retries.
  • ReactFiberThenable.js — tracks all thenables thrown during a render so that retries can wait on them.

Hydration

ReactFiberHydrationContext.js walks the existing host tree and matches it to fresh React work. There are two flavors:

  • Full-tree hydrationhydrateRoot(container, element).
  • Selective hydration — Suspense boundaries hydrate as their content arrives via streaming. The reconciler can pause hydration of a low-priority boundary if a click lands on a higher-priority one.

ReactFiberHydrationDiffs.js produces the rich "Server: ... Client: ..." mismatch error message.

Commit

ReactFiberCommitWork.js orchestrates three sub-passes:

  1. Before-mutation — snapshot DOM state (getSnapshotBeforeUpdate).
  2. MutationcommitMutationEffectsOnFiber walks the effect list, calling host config methods to apply the diff.
  3. LayoutuseLayoutEffect and componentDidMount/componentDidUpdate callbacks. Synchronous, before the browser paints.

After commit, passive effects (useEffect) are scheduled to flush after paint, via the scheduler's IdlePriority callback in flushPassiveEffects.

Integration points

  • Public surface to rendererspackages/react-reconciler/src/ReactFiberReconciler.js exports the Reconciler({ ...hostConfig }) factory used by every renderer. It returns a { createContainer, updateContainer, getPublicRootInstance, ... } API.
  • Imports from react — only ReactSharedInternals (the dispatcher / current owner) and the symbol set from shared/ReactSymbols. No direct reactreact-reconciler cycle.
  • Scheduler — every "yield to the browser" goes through Scheduler.unstable_scheduleCallback (re-exported via packages/react-reconciler/src/Scheduler.js).
  • DevToolspackages/react-reconciler/src/ReactFiberDevToolsHook.js publishes commit events (root committed, fiber unmounted, etc.) to the global __REACT_DEVTOOLS_GLOBAL_HOOK__. The hook is installed by the DevTools backend in react-devtools-shared.

Entry points for modification

  • Adding a new fiber tag: add to ReactWorkTags.js, then add a switch case to every getComponentNameFromFiber.js branch, the begin/complete work switches in ReactFiberBeginWork.js and ReactFiberCompleteWork.js, the commit walks in ReactFiberCommitWork.js, and the DevTools fiber walker in packages/react-devtools-shared/src/backend/fiber/renderer.js.
  • Adding a new flag bit: add to ReactFiberFlags.js, then audit commitMutationEffectsOnFiber and commitLayoutEffectsOnFiber in ReactFiberCommitWork.js for places that should observe it.
  • Adding a new lane: edit ReactFiberLane.js — every helper has to know about it. Be careful — the lane bit positions are part of the priority order.
  • Adding a new built-in hook: see packages/react.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

react-reconciler – React wiki | Factory