The Rendering Lifecycle

React is often described as a library that “updates the UI when state changes.” But how exactly does it do that efficiently? Understanding the rendering lifecycle—specifically the distinction between the Render Phase and the Commit Phase—is the key to optimizing performance and avoiding common pitfalls like infinite loops or unnecessary re-renders.

First Principles: The Physics of Rendering

Why does React exist? Why not just update the DOM directly?

The Cost of DOM Mutation

The browser’s DOM is slow to update because every change triggers a cascade of calculations:

  1. Recalculate Styles: The browser figures out which CSS rules apply.
  2. Reflow (Layout): The browser calculates the position and geometry of every element.
  3. Repaint: The browser paints pixels to the screen.

If you update the DOM 100 times in a loop, the browser might try to reflow 100 times. React solves this by batching updates and using a Virtual DOM.

The Virtual DOM (VDOM)

The Virtual DOM is a pure JavaScript object tree that mirrors the actual DOM.

  • Accessing JS Objects: ~0.0001ms
  • Accessing Real DOM: ~0.1ms (1000x slower)

React calculates changes in the cheap VDOM world and then applies the minimal set of changes to the real DOM in one go.

Phase 1: The Render Phase

The Render Phase is where React determines what changes need to be made.

  1. Trigger: A state update, parent re-render, or context change schedules a render.
  2. Calculation: React calls your component function.
  3. Reconciliation: React compares the new Virtual DOM tree returned by your component with the previous one.

Fiber Architecture

Since React 16, this phase is powered by Fiber. Fiber allows React to:

  • Pause, abort, or prioritize work.
  • Split rendering work into chunks (time-slicing).
  • Prioritize user interactions (clicks/input) over background data fetching.
graph TD A[State Change] --> B{Render Phase} B --> C[Call Component Function] C --> D[Generate New VDOM] D --> E[Diff with Old VDOM] E --> F{Changes Found?} F -->|No| G[End (No DOM Update)] F -->|Yes| H[Schedule Commit] style B fill:var(--accent-main),stroke:#fff,color:#fff style H fill:var(--green-500),stroke:#fff,color:#fff

Phase 2: The Commit Phase

The Commit Phase is where the side effects happen. This phase is synchronous and cannot be interrupted.

  1. Apply Changes: React applies the diffs calculated in the Render Phase to the real DOM.
  2. Layout Effects: useLayoutEffect runs synchronously after DOM mutations but before the browser paints.
  3. Paint: The browser paints the new UI to the screen.
  4. Passive Effects: useEffect runs asynchronously after the paint.

Rendering Lifecycle

[!NOTE] This module explores the core principles of Rendering Lifecycle, deriving solutions from first principles and hardware constraints to build world-class, production-ready expertise.

1. Interactive: Render Cycle Visualizer

Explore how React moves through the phases when state changes. Click “Trigger Update” to start the cycle.

Component State

Count: 0

Current Status

Idle
Waiting for interaction...
⚙️
Render
📝
Commit
🎨
Paint
Effect

2. Batching

React 18 introduced Automatic Batching. This means that multiple state updates occurring inside event handlers, promises, or timeouts are grouped into a single re-render to improve performance.

function handleClick() {
  setCount(c => c + 1);
  setFlag(f => !f);
  // React 18: Only ONE re-render happens here!
}

Prior to React 18, updates inside setTimeout or promises were not batched, causing two renders. Now, they are safe.

3. Optimizing the Render Cycle

Since rendering happens often, it must be fast. If a component is slow to render, it blocks the main thread.

React.memo

You can wrap a component in React.memo to skip re-rendering if its props haven’t changed.

const ExpensiveComponent = React.memo(function({ data }) {
  // Only re-renders if `data` prop changes (referential equality)
  return <div>{slowCalculation(data)}</div>;
});
⚠️ Warning: Don't optimize prematurely. React is very fast. Using React.memo adds comparison overhead. Only use it when you've identified a rendering bottleneck.

4. Key Takeaways

  • Render ≠ Update: Rendering is just calculating the diff.
  • Virtual DOM: The lightweight copy used for diffing.
  • Commit: When the DOM is actually touched.
  • Side Effects: Belong in useEffect, which runs after the paint.