Overview
Relevant Files
README.mdpackages/react/README.mdpackages/react-dom/README.mdpackages/react-reconciler/README.mdpackage.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. ProvidescreateRoot()for client-side rendering andrenderToPipeableStream()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 platformsreact-art- Renders to canvas and vector graphicsreact-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 serverreact-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.jspackages/react-reconciler/src/ReactFiberReconciler.jspackages/react-reconciler/src/ReactFiberBeginWork.jspackages/react-reconciler/src/ReactFiberCompleteWork.jspackages/react-reconciler/src/ReactFiberCommitWork.jspackages/react-reconciler/src/ReactFiberLane.jspackages/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:
- Begin Work (
ReactFiberBeginWork.js): Process a Fiber, reconcile children, create new Fibers - Complete Work (
ReactFiberCompleteWork.js): Bubble up effects, collect flags from children
Commit Phase applies changes to the DOM:
- Before Mutation: Run snapshot lifecycle methods
- Mutation: Insert/update/delete DOM nodes, run refs
- Layout: Run layout effects, measure DOM
- 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.lanesandfiber.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 insertedUpdate: Props or state changedDeletion: Node should be removedSnapshot: Capture DOM state before mutationCallback: 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.jspackages/react-reconciler/src/ReactFiberHooks.jspackages/react/src/ReactContext.jspackages/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 instancebaseState- The state before any pending updatesbaseQueue- Queued updates that haven't been processedqueue- The update queue for state changesnext- 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 functiondeps- Dependency arrayinst- 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.jspackages/react-dom/src/client/ReactDOMRoot.jspackages/react-dom-bindings/src/client/ReactDOMComponent.jspackages/react-dom-bindings/src/events/DOMPluginEventSystem.jspackages/react-dom-bindings/src/events/ReactDOMEventListener.jspackages/react-dom-bindings/src/events/SyntheticEvent.jspackages/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:
- Container Setup: Creates an internal fiber root and marks the DOM container as a React root
- 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
mouseenterandmouseleave(non-bubbling) - ChangeEventPlugin: Normalizes
changeevents across form elements - SelectEventPlugin: Handles text selection in inputs
- BeforeInputEventPlugin: Provides
beforeinputevent 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.jspackages/react-server/src/ReactFlightServer.jspackages/react-dom/src/server/ReactDOMFizzServerNode.jspackages/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, andflushCompletedQueues()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;drainevents 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 aPostponedState
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.jspackages/scheduler/src/SchedulerPriorities.jspackages/scheduler/src/SchedulerMinHeap.jspackages/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
delayoption 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.mdcompiler/docs/DESIGN_GOALS.mdcompiler/packages/babel-plugin-react-compiler/srccompiler/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 toReact.__COMPILER_RUNTIME.cin 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-devtoolspackages/react-devtools-corepackages/react-devtools-inlinepackages/react-devtools-sharedpackages/react-test-rendererpackages/react-refreshpackages/internal-test-utilspackages/jest-reactpackages/react-debug-toolspackages/dom-event-testing-librarypackages/eslint-plugin-react-hookspackages/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. Runreact-devtoolsglobally 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. ProvidesconnectToDevTools()for renderers andstartServer()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 -
SchedulerMockfor 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
.eslintrcformat - Configurable for custom hooks via
additionalHooksregex
React Suspense Test Utils
Experimental utilities for testing Suspense features. Unstable API; use at your own risk.
Architecture Overview
Loading diagram...