Install

facebook/react

React Core & Compiler Wiki

Last updated on Dec 18, 2025 (Commit: 65eec42)

Overview

Relevant Files
  • README.md
  • packages/react/README.md
  • packages/react-dom/README.md
  • packages/react-reconciler/README.md
  • package.json

React is a JavaScript library for building user interfaces with a declarative, component-based architecture. This repository contains the core React runtime, renderers for different platforms, and supporting tools for development and optimization.

Core Architecture

The React ecosystem is organized as a monorepo with multiple specialized packages:

Core Packages:

  • react - Defines React components, hooks, and the core API. Contains only the logic for creating components; rendering is handled by separate packages.
  • react-dom - The primary renderer for web browsers. Provides createRoot() for client-side rendering and renderToPipeableStream() for server-side rendering.
  • react-reconciler - An experimental package for creating custom renderers. Implements the diffing algorithm and scheduling logic that all renderers use.
  • scheduler - Cooperative scheduling for the browser environment. Manages task prioritization and time-slicing for rendering work.

Specialized Renderers:

  • react-native-renderer - Renders to native mobile platforms
  • react-art - Renders to canvas and vector graphics
  • react-test-renderer - Renders to an in-memory tree for testing

Server & Streaming:

  • react-server - Experimental package for streaming server rendering (Fizz and Flight protocols)
  • react-client - Consumes streaming models from the server
  • react-server-dom-* - Various implementations for different bundlers and runtimes

Key Concepts

Declarative UI: Components describe what the UI should look like. React handles updates efficiently when state changes.

Component-Based: Build encapsulated components that manage their own state, then compose them into complex UIs.

Render Phase & Commit Phase: React separates work into two phases. The render phase (interruptible) builds a new tree, and the commit phase (synchronous) applies changes to the DOM.

Fiber Architecture: React uses a fiber-based reconciliation algorithm that enables features like error boundaries, Suspense, and concurrent rendering.

Development Workflow

The repository uses Yarn workspaces for monorepo management. Key scripts include:

  • Build: Compiles packages using Rollup and Babel
  • Test: Runs Jest tests across packages
  • Lint: Validates code with ESLint and Flow type checking
  • Release: Publishes packages to npm with version management

Getting Started

For web development, install both react and react-dom:

import { createRoot } from 'react-dom/client';

function App() {
  return <div>Hello World</div>;
}

const root = createRoot(document.getElementById('root'));
root.render(<App />);

For custom renderers, use react-reconciler to implement a host config that defines how to create, update, and remove nodes in your target environment.

Loading diagram...

Architecture & Fiber System

Relevant Files
  • packages/react-reconciler/src/ReactFiber.js
  • packages/react-reconciler/src/ReactFiberReconciler.js
  • packages/react-reconciler/src/ReactFiberBeginWork.js
  • packages/react-reconciler/src/ReactFiberCompleteWork.js
  • packages/react-reconciler/src/ReactFiberCommitWork.js
  • packages/react-reconciler/src/ReactFiberLane.js
  • packages/react-reconciler/src/ReactFiberWorkLoop.js

What is a Fiber?

A Fiber is the core unit of work in React's reconciliation engine. Each component instance in your app tree has a corresponding Fiber node that tracks its state, props, and effects. Unlike the old stack reconciler, Fibers enable React to pause, abort, or reuse work, making concurrent rendering possible.

Key Fiber properties include:

  • Tree structure: return (parent), child (first child), sibling (next sibling)
  • Component data: tag (component type), type, key, elementType
  • State: pendingProps, memoizedProps, memoizedState, updateQueue
  • Effects: flags (what changed), subtreeFlags, deletions
  • Scheduling: lanes (priority), childLanes (child priorities)
  • Double buffering: alternate (the other version of this Fiber)

The Reconciliation Algorithm

React uses a two-phase rendering model:

Render Phase (pausible) → Commit Phase (synchronous)

Render Phase traverses the Fiber tree and determines what changed:

  1. Begin Work (ReactFiberBeginWork.js): Process a Fiber, reconcile children, create new Fibers
  2. Complete Work (ReactFiberCompleteWork.js): Bubble up effects, collect flags from children

Commit Phase applies changes to the DOM:

  1. Before Mutation: Run snapshot lifecycle methods
  2. Mutation: Insert/update/delete DOM nodes, run refs
  3. Layout: Run layout effects, measure DOM
  4. Passive: Run effect cleanup and setup functions

The Lane System

React uses a 32-bit bitmask called Lanes to represent update priorities. Each bit is a lane:

SyncLane (0b10)              // Highest priority (user input)
InputContinuousLane (0b1000) // Medium priority (scroll, drag)
DefaultLane (0b100000)       // Normal priority (data fetching)
TransitionLanes              // Low priority (non-urgent updates)
IdleLane                     // Lowest priority (background work)

Lanes enable React to:

  • Batch updates of the same priority together
  • Interrupt low-priority work when high-priority updates arrive
  • Retry suspended work at appropriate times
  • Track which Fibers need updates via fiber.lanes and fiber.childLanes

Work Loop & Scheduling

The work loop (ReactFiberWorkLoop.js) is the heart of rendering:

scheduleUpdateOnFiber() → ensureRootIsScheduled() → Scheduler
  ↓
performUnitOfWork() loop (render phase)
  ↓
finishConcurrentRender() (commit phase)

For concurrent rendering, React yields to the browser every 5ms (or 25ms for transitions) to keep animations smooth. For sync rendering, it processes the entire tree without yielding.

Double Buffering & Alternate Fibers

React maintains two Fiber trees:

  • Current tree: The last committed version (what's on screen)
  • Work-in-progress tree: Being built during render phase

After rendering completes, the trees swap. This allows React to:

  • Reuse Fiber objects (memory efficient)
  • Safely discard incomplete renders
  • Compare old and new props/state efficiently
Loading diagram...

Effect Flags & Subtree Flags

Each Fiber tracks what needs to happen via flags:

  • Placement: Node needs to be inserted
  • Update: Props or state changed
  • Deletion: Node should be removed
  • Snapshot: Capture DOM state before mutation
  • Callback: Run lifecycle methods

Subtree flags bubble up from children, so parents know if any descendant changed. This optimization skips traversing unchanged subtrees during commit.

Hooks & State Management

Relevant Files
  • packages/react/src/ReactHooks.js
  • packages/react-reconciler/src/ReactFiberHooks.js
  • packages/react/src/ReactContext.js
  • packages/react-reconciler/src/ReactFiberNewContext.js

React's hooks and state management system is built on a fiber-based architecture where state is stored as a linked list on each fiber's memoizedState field. This design enables efficient state updates, dependency tracking, and context propagation.

Hook Storage Architecture

Hooks are stored as a linked list on the fiber's memoizedState field. Each hook is a node containing:

  • memoizedState - The current state value or effect instance
  • baseState - The state before any pending updates
  • baseQueue - Queued updates that haven't been processed
  • queue - The update queue for state changes
  • next - Pointer to the next hook in the list

During render, React maintains two hook pointers: currentHook (from the previous render) and workInProgressHook (being built for the current render). This dual-pointer system enables React to compare old and new hook states.

State Updates and Queues

State updates flow through an UpdateQueue structure:

type UpdateQueue<S, A> = {
  pending: Update<S, A> | null,
  lanes: Lanes,
  dispatch: (A => mixed) | null,
  lastRenderedReducer: ((S, A) => S) | null,
  lastRenderedState: S | null,
};

Updates are batched in a circular linked list and processed during render. React uses lanes to prioritize updates—urgent updates (like user input) have higher priority than deferred updates (like transitions).

Effects Management

Effects are stored in a circular linked list on the fiber's updateQueue.lastEffect. Each effect tracks:

  • tag - Flags indicating effect type (Passive, Layout, Insertion)
  • create - The effect function
  • deps - Dependency array
  • inst - Effect instance with destroy function

React processes effects in phases: useInsertionEffect runs before layout, useLayoutEffect runs synchronously after DOM mutations, and useEffect runs asynchronously after paint.

Context Dependency Tracking

Context reads are tracked through a dependency chain on the fiber's dependencies field:

type ContextDependency<T> = {
  context: ReactContext<T>,
  memoizedValue: T,
  next: ContextDependency<mixed> | null,
};

When a component reads context via useContext() or readContext(), React records the context and its current value. When a provider's value changes, React traverses the dependency chain to find affected consumers and schedules updates on them.

Dispatcher Pattern

The public hook API (useState, useEffect, etc.) delegates to a dispatcher object stored in ReactSharedInternals.H. This allows React to swap implementations based on the render phase:

  • Mount phase - Hooks initialize state and effects
  • Update phase - Hooks retrieve existing state and apply updates
  • Rerender phase - Hooks handle errors and re-execute logic

This pattern enables React to enforce the Rules of Hooks and provide helpful error messages when hooks are called outside valid contexts.

Memoization and Caching

React uses a memo cache for useMemo and useCallback optimization. The cache is stored on updateQueue.memoCache and uses a copy-on-write strategy: when a component re-renders, the cache is cloned before modifications to preserve the previous render's cache if the render is interrupted.

Loading diagram...

DOM Integration & Events

Relevant Files
  • packages/react-dom/src/client/ReactDOMClient.js
  • packages/react-dom/src/client/ReactDOMRoot.js
  • packages/react-dom-bindings/src/client/ReactDOMComponent.js
  • packages/react-dom-bindings/src/events/DOMPluginEventSystem.js
  • packages/react-dom-bindings/src/events/ReactDOMEventListener.js
  • packages/react-dom-bindings/src/events/SyntheticEvent.js
  • packages/react-dom-bindings/src/events/EventRegistry.js

Root Initialization & Event Delegation

When you call ReactDOM.createRoot(), React sets up a connection between your component tree and the DOM. The root initialization process in ReactDOMRoot.js performs two critical steps:

  1. Container Setup: Creates an internal fiber root and marks the DOM container as a React root
  2. Event Listener Registration: Calls listenToAllSupportedEvents() to attach event listeners at the root level

This delegation strategy is key to React's event system. Instead of attaching listeners to every DOM element, React attaches a single listener per event type at the root container. When an event fires, React's system determines which component should handle it.

Event System Architecture

React's event system uses a plugin-based architecture with multiple layers:

// Event flow: Native DOM Event → React Listener → Plugin System → Component Handler

// 1. Native event fires on DOM element
// 2. Root listener (attached at container) captures it
// 3. DOMPluginEventSystem extracts events via plugins
// 4. Synthetic event created and dispatched to component handlers

The system includes several event plugins:

  • SimpleEventPlugin: Handles basic events like click, focus, change
  • EnterLeaveEventPlugin: Synthesizes mouseenter and mouseleave (non-bubbling)
  • ChangeEventPlugin: Normalizes change events across form elements
  • SelectEventPlugin: Handles text selection in inputs
  • BeforeInputEventPlugin: Provides beforeinput event support
  • FormActionEventPlugin: Manages form submission and action handling

Synthetic Events

React wraps native DOM events in SyntheticEvent objects. These provide:

  • Cross-browser normalization: Consistent behavior across browsers
  • Event pooling optimization: Reusable event objects (in some versions)
  • Standard DOM API: Methods like preventDefault(), stopPropagation(), persist()
// Synthetic event structure
{
  _reactName: 'onClick',        // React event name
  type: 'click',                // DOM event type
  nativeEvent: {...},           // Original DOM event
  target: domElement,           // Event target
  currentTarget: domElement,    // Current handler's element
  // ... normalized properties from Interface
}

Event Propagation & Capture Phases

React supports both bubble and capture phases through event registration:

  • Bubble phase (default): onClick, onChange — handlers fire bottom-up
  • Capture phase: onClickCapture, onChangeCapture — handlers fire top-down

The system tracks which phase is active via EventSystemFlags and processes dispatch queues accordingly. Capture phase listeners execute first, then bubble phase listeners traverse the component tree upward.

Non-Delegated Events

Some events cannot be delegated (e.g., play, pause, scroll). For these, React attaches listeners directly to the target element via listenToNonDelegatedEvent(). This ensures proper event handling for events that don't bubble or have special semantics.

Server-Side Rendering & Streaming

Relevant Files
  • packages/react-server/src/ReactFizzServer.js
  • packages/react-server/src/ReactFlightServer.js
  • packages/react-dom/src/server/ReactDOMFizzServerNode.js
  • packages/react-server/src/ReactFlightActionServer.js

React provides two complementary server-side rendering systems: Fizz for streaming HTML and Flight for Server Components. Together, they enable efficient server-side rendering with progressive enhancement and data streaming.

Fizz: HTML Streaming

Fizz renders React components to HTML on the server and streams the output progressively. This allows the browser to display content before the entire render completes, improving perceived performance.

Key concepts:

  • Request lifecycle: createRequest() initializes a render request with callbacks for different completion stages (onShellReady, onAllReady, onError)
  • Streaming pipeline: startWork() begins rendering, startFlowing() connects to a destination stream, and flushCompletedQueues() writes buffered HTML chunks
  • Suspense boundaries: Incomplete components render as placeholders, then stream their content when ready
  • Backpressure handling: stopFlowing() pauses output when the destination stream is full; drain events resume

Example usage:

const {pipe, abort} = renderToPipeableStream(<App />, {
  onShellReady() {
    res.statusCode = 200;
    res.setHeader('Content-Type', 'text/html');
    pipe(res);
  },
  onError(error) {
    console.error(error);
  },
});

Flight: Server Components

Flight serializes React Server Components (components that run only on the server) into a compact binary format. Server Components can fetch data, access secrets, and render client components without exposing sensitive logic.

Key concepts:

  • Component types: Server Components (default) execute on the server; Client Components (marked with "use client") run in the browser
  • Serialization: createRequest() builds a request, startWork() renders the component tree, flushCompletedChunks() writes serialized chunks
  • Chunk ordering: Import chunks, hints, debug metadata, then model data—enabling early preloading
  • Server Actions: Functions marked with "use server" can be called from the client; Flight handles serialization and routing

Streaming Architecture

Loading diagram...

Postponement & Resumption

Fizz supports postponement: pausing render at Suspense boundaries and resuming later. This enables:

  • Prerendering: Generate static HTML shells for crawlers
  • Resumption: Continue rendering from a saved state when new data arrives
  • createPrerenderRequest() tracks postponed holes; resumeRequest() resumes from a PostponedState

Error Handling

Both systems provide granular error callbacks:

  • onError(): Recoverable errors in components (logged, component falls back to client rendering)
  • onShellError(): Errors before streaming starts (send error page)
  • onFatalError(): Unrecoverable errors (abort entire request)

Errors are serialized with stack traces and component information for debugging.

Scheduler & Task Prioritization

Relevant Files
  • packages/scheduler/src/Scheduler.js
  • packages/scheduler/src/SchedulerPriorities.js
  • packages/scheduler/src/SchedulerMinHeap.js
  • packages/react-reconciler/src/ReactFiberConcurrentUpdates.js

The Scheduler is React's task prioritization and execution engine. It manages when and how work gets executed on the main thread, ensuring high-priority updates (like user input) don't get blocked by lower-priority work (like data fetching).

Priority Levels

React defines six priority levels, each with different timeout values:

NoPriority = 0                    // Not used for scheduling
ImmediatePriority = 1             // Timeout: -1 (expires immediately)
UserBlockingPriority = 2          // Timeout: 250ms (user interactions)
NormalPriority = 3                // Timeout: 5000ms (default)
LowPriority = 4                   // Timeout: 10000ms (data fetching)
IdlePriority = 5                  // Timeout: 1073741823ms (never expires)

Higher priority tasks execute before lower priority ones. Tasks also expire based on their timeout—an expired task will execute even if higher-priority work exists.

Task Queues & Min Heap

The Scheduler maintains two queues:

  • taskQueue: Immediate tasks ready to execute
  • timerQueue: Delayed tasks waiting for their start time

Both use a min heap data structure for efficient priority ordering. The heap compares tasks by sortIndex (expiration time for immediate tasks, start time for delayed tasks), then by insertion order (id) to maintain stability.

// Min heap operations
push(heap, task)      // Add task, maintain heap property
pop(heap)             // Remove highest-priority task
peek(heap)            // View highest-priority task without removing

Work Loop & Time Slicing

The Scheduler's workLoop executes tasks in priority order while respecting frame boundaries:

while (currentTask !== null) {
  if (currentTask.expirationTime > currentTime && shouldYieldToHost()) {
    break;  // Yield to browser for user events
  }
  const continuationCallback = callback(didUserCallbackTimeout);
  if (continuationCallback) {
    currentTask.callback = continuationCallback;
    return true;  // More work remains
  }
}

Tasks can return a continuation callback to resume later. The Scheduler yields every 5ms by default to allow the browser to handle user input, paint, and other critical work.

Concurrent Updates Integration

When updates occur during rendering, ReactFiberConcurrentUpdates queues them separately. Once the current render completes, finishQueueingConcurrentUpdates() merges these updates into the fiber's update queue, ensuring they're processed in the correct order.

Key Concepts

  • Expiration: Tasks with earlier expiration times execute first, preventing starvation
  • Yielding: The Scheduler yields to the browser every 5ms to keep the UI responsive
  • Delayed Tasks: Tasks with a delay option go to the timer queue until their start time arrives
  • Cancellation: Tasks can be canceled by nulling their callback; they remain in the queue but are skipped during execution

React Compiler & Optimization

Relevant Files
  • compiler/README.md
  • compiler/docs/DESIGN_GOALS.md
  • compiler/packages/babel-plugin-react-compiler/src
  • compiler/packages/react-compiler-runtime/src/index.ts

React Compiler is an optimizing compiler that automatically memoizes React components and hooks, ensuring minimal re-renders when state changes. It eliminates the need for manual React.memo(), useMemo(), and useCallback() by analyzing code and inserting memoization automatically.

Core Architecture

The compiler transforms code through a multi-stage pipeline:

Loading diagram...

Compilation Pipeline

1. Lowering (BuildHIR): Converts Babel AST into HIR (High-level Intermediate Representation), a control-flow graph of basic blocks. Preserves JavaScript semantics including break/continue resolution and order-of-evaluation.

2. SSA Conversion: Transforms HIR into Static Single Assignment form, ensuring each variable is assigned exactly once. Introduces phi functions at control-flow merge points.

3. Validation: Checks that code follows React rules—no conditional hook calls, no setState in render, proper hook naming conventions.

4. Type Inference: Conservative type analysis identifies hooks, primitives, and other key data types relevant for optimization.

5. Reactive Scope Inference: Determines groups of values that mutate together, creating independently memoizable units. Four-pass process aligns scopes to block boundaries and merges overlapping scopes.

6. Optimization: Dead code elimination, constant propagation, instruction reordering, and scope pruning reduce overhead.

7. Codegen: Converts ReactiveFunction back to Babel AST with inserted memoization checks using useMemoCache().

Runtime Support

The react-compiler-runtime package provides essential runtime utilities:

  • c(size): Allocates a memo cache array of given size. Polyfill for React versions < 19; delegates to React.__COMPILER_RUNTIME.c in React 19+.
  • $dispatcherGuard(): Runtime validation of hook call rules—prevents conditional hooks, renamed hooks, and indirect hook invocations.
  • $reset(): Clears memo cache slots between renders.
  • $structuralCheck(): Deep equality checking for dependency tracking (development mode).

Memoization Strategy

Compiled code uses a memo cache array ($) to store computed values and their dependencies:

const $ = c(4);  // Allocate 4 cache slots
if ($[0] !== dependency) {
  result = expensiveComputation(dependency);
  $[0] = dependency;
  $[1] = result;
} else {
  result = $[1];
}

Each reactive scope gets two slots: one for dependencies, one for the memoized value. The compiler automatically determines which values need memoization based on dependency analysis.

Key Design Principles

  • High-level output: Retains original code constructs (if vs ternary, for vs while) for debuggability and compact output.
  • No annotations required: Works on idiomatic React code following the Rules of React.
  • Predictable performance: Bounds re-rendering by default without requiring developer intervention.
  • Neutral startup: Minimal code size increase and memoization overhead.

DevTools, Testing & Utilities

Relevant Files
  • packages/react-devtools
  • packages/react-devtools-core
  • packages/react-devtools-inline
  • packages/react-devtools-shared
  • packages/react-test-renderer
  • packages/react-refresh
  • packages/internal-test-utils
  • packages/jest-react
  • packages/react-debug-tools
  • packages/dom-event-testing-library
  • packages/eslint-plugin-react-hooks
  • packages/react-suspense-test-utils

React DevTools

React DevTools is a browser extension and standalone application for inspecting React component hierarchies, props, state, and hooks. The ecosystem includes multiple packages serving different environments:

  • react-devtools - Standalone desktop app for debugging React Native, mobile browsers, and embedded webviews. Run react-devtools globally to launch the UI, then connect your app via WebSocket on port 8097.
  • react-devtools-core - Low-level backend and frontend APIs for custom integrations. Provides connectToDevTools() for renderers and startServer() for UI hosting.
  • react-devtools-inline - Embeds DevTools into browser-based tools like CodeSandbox and StackBlitz. Supports same-origin iframes, sandboxed iframes, and custom messaging protocols.
  • react-devtools-shared - Shared code between core, extensions, and inline packages (not published separately).

Testing Utilities

Internal Test Utils

internal-test-utils provides core testing infrastructure for React's own test suite:

  • Scheduler mocking - SchedulerMock for controlling async work and testing concurrent features
  • Async assertions - waitFor(), waitForAll() for verifying scheduler logs and event sequences
  • Console mocking - Capture and assert on console logs, warnings, and errors
  • DOM utilities - ReactJSDOM, simulateBrowserEventDispatch() for event testing
  • Debug info - getDebugInfo() for inspecting component internals

Test Renderer (Deprecated)

react-test-renderer renders components to JavaScript objects without DOM or native environments. Deprecated as of React 19 in favor of @testing-library/react and standard DOM APIs.

Jest React

jest-react provides Jest matchers and utilities for react-test-renderer snapshots.

DOM Event Testing Library

dom-event-testing-library simplifies testing pointer interactions and DOM events:

  • High-level API for realistic event sequences (e.g., pointerdown, pointerup)
  • Handles PointerEvent API fallbacks for mouse and touch
  • Supports multi-touch scenarios and emulated mouse events
  • Configurable event properties with sensible defaults

Development Tools

React Refresh

react-refresh implements Fast Refresh wiring for bundlers. Enables editing React components without losing state during development. Primarily for bundler plugin developers.

React Debug Tools

Experimental package for debugging React renderers. Provides low-level introspection APIs. API is unstable and not versioned like React core.

ESLint Plugin React Hooks

Official ESLint plugin enforcing the Rules of Hooks and React best practices:

  • Core rules - rules-of-hooks, exhaustive-deps
  • Compiler rules - Purity, immutability, error boundaries, and more
  • Supports both flat config (ESLint 9+) and legacy .eslintrc format
  • Configurable for custom hooks via additionalHooks regex

React Suspense Test Utils

Experimental utilities for testing Suspense features. Unstable API; use at your own risk.

Architecture Overview

Loading diagram...