What Happens During Mounting in React: A Deep Dive into the Source Code

During mounting in React, the reconciler creates a Fiber node, executes the component's lifecycle methods (constructor → getDerivedStateFromProps → render), constructs the DOM tree via the host config, and commits side-effects like componentDidMount and useEffect callbacks.

Mounting in React is the process by which a component is instantiated and inserted into the DOM for the first time. This article examines the internal mechanics of the React repository (facebook/react) to explain exactly what occurs during this critical phase.

The Mounting Pipeline: Step-by-Step

React's mounting process is orchestrated by the reconciler (react-reconciler) and follows a strict sequence from Fiber creation to side-effect commitment.

1. Fiber Creation in beginWork

The mounting process begins in ReactFiberBeginWork.js. When React encounters a new component for the first time, beginWork creates a new Fiber node to represent it. This Fiber tracks the component's type, props, and state throughout its lifetime.

For root mounts, the reconciler calls mountHostRootWithoutHydrating to initialize the Fiber tree before descending into individual components.

2. Class Component Mount Lifecycle

For class components, React invokes mountClassInstance in ReactFiberClassComponent.js. This function executes the classic mounting sequence:

  1. Constructor – Initializes state and binds methods
  2. getDerivedStateFromProps – Computes state from incoming props (runs before every render)
  3. componentWillMount (legacy) – Deprecated lifecycle still invoked for backward compatibility
  4. Render – Returns the React element tree

The component instance is stored on the Fiber's stateNode property, linking the Fiber to the actual class instance.

3. Function Component Mount with Hooks

Function components follow a different path through ReactFiberHooks.js. When mounting a function component, React calls mountWorkInProgressHook to initialize the hooks linked list.

  • mountState creates the initial state cell
  • mountEffect schedules side-effects (the equivalent of componentDidMount for hooks)
  • The component function executes, returning JSX that becomes child Fibers

Each hook is appended to a singly-linked list stored on the Fiber's memoizedState property.

4. Host Tree Construction

As the reconciler descends the component tree, it encounters host components (DOM elements like div or span). In ReactFiberConfigDOM.js, React calls createInstance to generate actual DOM nodes.

The process follows this pattern:

  1. createInstance(type, props, rootContainer, hostContext, internalHandle) creates the DOM element
  2. appendChild(parent, child) recursively builds the tree structure
  3. Props are applied via setInitialProperties before insertion

This phase constructs the physical DOM tree that the user will eventually see, though it remains detached from the document until the commit phase.

5. Commit Phase and Side Effects

After the entire tree is built, React enters the commit phase via ReactFiberCommitHostEffects.js. This phase is synchronous and applies changes to the host environment.

commitMount in ReactFiberConfigDOM.js handles host component side-effects:

  • Auto-focus logic for elements with the autoFocus attribute
  • Image loading triggers for img tags
  • Form validation setup

For class components, the reconciler checks for the Update flag set during mountClassInstance and invokes componentDidMount.

For hooks, commitHookEffectListMount processes the effect queue created during mountEffect, executing useEffect callbacks after the DOM is attached.

Key Source Files in the React Repository

File Primary Role in Mounting Source Link
packages/react-reconciler/src/ReactFiberBeginWork.js Drives the beginWork algorithm; creates new Fibers and decides which mount function to call View on GitHub
packages/react-reconciler/src/ReactFiberClassComponent.js Implements mountClassInstance – the full class-component mount lifecycle View on GitHub
packages/react-reconciler/src/ReactFiberHooks.js Hook creation (mountState, mountEffect, etc.) for function components View on GitHub
packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js Host-config for the DOM: createInstance, appendChild, and commitMount View on GitHub
packages/react-reconciler/src/ReactFiberCommitHostEffects.js Executes all commit side-effects including componentDidMount flag handling View on GitHub
packages/react-reconciler/src/ReactFiberCompleteWork.js Finalizes a fiber after children are processed; marks the fiber as mounted View on GitHub

Practical Code Examples

Class Component Mount Sequence

The following example demonstrates the exact lifecycle sequence executed by mountClassInstance in ReactFiberClassComponent.js:

// src/MyComponent.js
import React from 'react';

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    console.log('1. constructor');
    this.state = { value: props.initialValue };
  }

  static getDerivedStateFromProps(nextProps, prevState) {
    console.log('2. getDerivedStateFromProps');
    return null;
  }

  componentWillMount() {
    // Legacy lifecycle - still called for backward compatibility
    console.log('3. componentWillMount (deprecated)');
  }

  render() {
    console.log('4. render');
    return <div ref={el => this.divRef = el}>{this.state.value}</div>;
  }

  componentDidMount() {
    console.log('5. componentDidMount');
    // DOM is now available via this.divRef
    console.log('DOM node:', this.divRef);
  }
}

export default MyComponent;

Console output order:


1. constructor
2. getDerivedStateFromProps
3. componentWillMount (deprecated)
4. render
5. componentDidMount

This sequence corresponds exactly to the implementation in mountClassInstance, where the reconciler executes each method in order before marking the fiber for commit effects.

Function Component Mount Sequence

Function components use hooks to achieve the same mounting behavior. The mountWorkInProgressHook function in ReactFiberHooks.js initializes the hook state during the first render:

// src/Counter.js
import React, { useState, useEffect, useRef } from 'react';

export default function Counter() {
  const [count, setCount] = useState(0);
  const buttonRef = useRef(null);
  
  console.log('1. render - count:', count);

  // Equivalent to componentDidMount + componentDidUpdate
  useEffect(() => {
    console.log('2. useEffect - DOM updated');
    console.log('Button element:', buttonRef.current);
    
    // Cleanup function (equivalent to componentWillUnmount)
    return () => {
      console.log('Cleanup before next effect or unmount');
    };
  }, []); // Empty array = mount only

  return (
    <button ref={buttonRef} onClick={() => setCount(c => c + 1)}>
      Count: {count}
    </button>
  );
}

Console output on mount:


1. render - count: 0
2. useEffect - DOM updated
Button element: <button>...</button>

Internally, mountState initializes the state cell during the render phase, while mountEffect queues the callback in the fiber's effect list. During the commit phase, commitHookEffectListMount executes the effect callback after the DOM nodes are attached via commitMount.

Summary

  • Mounting in React is a two-phase process: the render phase (building the Fiber tree and creating host instances) and the commit phase (attaching to the DOM and running side-effects).
  • Class components follow the sequence constructor → getDerivedStateFromProps → componentWillMount → render → componentDidMount, implemented in mountClassInstance within ReactFiberClassComponent.js.
  • Function components use the hooks system via mountWorkInProgressHook in ReactFiberHooks.js, where useState initializes during render and useEffect callbacks execute during commit.
  • Host tree construction occurs through createInstance and appendChild in ReactFiberConfigDOM.js, while side-effects like autoFocus and componentDidMount are processed in commitMount during the commit phase.

Frequently Asked Questions

What is the difference between mounting and rendering in React?

Rendering is the process of invoking your component function or method to determine what UI should look like, which occurs during the render phase. Mounting is the complete lifecycle of inserting a new component into the DOM for the first time, which includes both the initial render and the subsequent commit phase where React actually creates DOM nodes and runs effects like componentDidMount.

Does useEffect run during the mounting phase?

Yes, but specifically during the commit phase of mounting. While useEffect is declared during the render phase via mountEffect in ReactFiberHooks.js, the callback function does not execute until after the DOM has been updated. This occurs when commitHookEffectListMount processes the effect list, making it the hooks equivalent of componentDidMount.

Why is componentWillMount deprecated?

componentWillMount was deprecated because it encouraged patterns that could break with React's concurrent rendering features. Since this method fired immediately before rendering, developers often used it for side-effects that should have occurred after mount, or for subscriptions that could leak if the render was interrupted. Modern code should use constructor for initialization and componentDidMount (or useEffect) for side-effects, as these align with React's two-phase commit architecture.

How does React handle errors during mounting?

React uses error boundaries to catch JavaScript errors during the mounting phase. If an error occurs in constructor, render, or componentDidMount, React will unmount the entire tree and attempt to mount the nearest error boundary's fallback UI. Internally, this is handled by the reconciler's error handling logic in ReactFiberBeginWork.js and the commit phase error capture mechanisms, ensuring that a single component failure does not crash the entire application.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →