← Back to all projects

LEARN REACT INTERNALS

Learn React Internals: How React Really Works

Goal: Deeply understand React’s internal architecture—Virtual DOM, Fiber reconciliation, hooks implementation, JSX compilation, event system, and concurrent rendering.


Why Learn React Internals?

Most React developers use React like a black box. They know useState updates state and triggers a re-render, but not how. Understanding React’s internals transforms you from a React user to a React master:

  • Debug faster: When you understand the render cycle, you spot issues immediately
  • Write performant code: Knowing Fiber helps you avoid unnecessary re-renders
  • Ace interviews: “How does React work internally?” is a senior-level question
  • Contribute to React: The React team welcomes informed contributors
  • Build similar tools: Understanding the patterns lets you build your own libraries

Core Concept Analysis

The Big Picture: React’s Architecture

┌─────────────────────────────────────────────────────────────────────┐
│                           YOUR CODE                                  │
│                                                                      │
│   const App = () => {                                               │
│     const [count, setCount] = useState(0);                          │
│     return <button onClick={() => setCount(c => c+1)}>{count}</button>│
│   }                                                                  │
└─────────────────────────────────────────────────────────────────────┘
                                 │
                                 ▼
┌─────────────────────────────────────────────────────────────────────┐
│                        BABEL/COMPILER                                │
│                                                                      │
│   JSX → React.createElement() calls                                 │
│   <button>  →  createElement('button', {onClick: ...}, count)       │
└─────────────────────────────────────────────────────────────────────┘
                                 │
                                 ▼
┌─────────────────────────────────────────────────────────────────────┐
│                      REACT ELEMENT TREE                              │
│                      (Virtual DOM)                                   │
│                                                                      │
│   { type: 'button', props: { onClick: fn, children: 0 } }          │
└─────────────────────────────────────────────────────────────────────┘
                                 │
                                 ▼
┌─────────────────────────────────────────────────────────────────────┐
│                      FIBER TREE                                      │
│                      (Work Units)                                    │
│                                                                      │
│   FiberNode {                                                        │
│     type: 'button',                                                 │
│     stateNode: <actual DOM node>,                                   │
│     memoizedState: { hooks: [...] },                                │
│     effectTag: UPDATE,                                              │
│     ...                                                             │
│   }                                                                  │
└─────────────────────────────────────────────────────────────────────┘
                                 │
                                 ▼
┌─────────────────────────────────────────────────────────────────────┐
│                      RECONCILER                                      │
│                                                                      │
│   1. Render Phase (can be interrupted)                              │
│      - Build Work-in-Progress tree                                  │
│      - Diff with current tree                                       │
│      - Collect effects (DOM updates needed)                         │
│                                                                      │
│   2. Commit Phase (synchronous)                                      │
│      - Apply all DOM mutations                                      │
│      - Run effects (useEffect, useLayoutEffect)                     │
└─────────────────────────────────────────────────────────────────────┘
                                 │
                                 ▼
┌─────────────────────────────────────────────────────────────────────┐
│                      ACTUAL DOM                                      │
│                                                                      │
│   <button>0</button>                                                │
└─────────────────────────────────────────────────────────────────────┘

Key Concepts Explained

1. JSX Compilation

JSX is syntactic sugar. Babel transforms it into function calls:

// You write:
<div className="container">
  <h1>Hello</h1>
  <p>World</p>
</div>

// Babel compiles to:
React.createElement('div', { className: 'container' },
  React.createElement('h1', null, 'Hello'),
  React.createElement('p', null, 'World')
);

// Which returns a React Element (plain object):
{
  type: 'div',
  props: {
    className: 'container',
    children: [
      { type: 'h1', props: { children: 'Hello' } },
      { type: 'p', props: { children: 'World' } }
    ]
  }
}

New JSX Transform (React 17+): No longer requires import React because Babel auto-imports jsx from react/jsx-runtime.

2. Virtual DOM

The Virtual DOM is a JavaScript representation of the actual DOM. It’s a tree of plain objects (React Elements).

// Virtual DOM node (React Element)
const element = {
  type: 'div',           // Tag name or component function
  props: {               // Attributes + children
    className: 'app',
    children: [...]
  },
  key: null,             // For reconciliation
  ref: null              // DOM reference
};

Why Virtual DOM?

  • DOM operations are slow; JS operations are fast
  • Batch multiple changes into single DOM update
  • Enables diffing algorithm (only update what changed)
  • Platform agnostic (same model for web, native, VR)

3. Fiber Architecture

Fiber is React’s reconciliation engine (since React 16). Each Fiber is a unit of work representing a component instance.

// Simplified Fiber Node structure
FiberNode = {
  // Identity
  type: Function | String,     // Component function or tag name
  key: String | null,

  // Relationships (tree structure)
  child: Fiber | null,         // First child
  sibling: Fiber | null,       // Next sibling
  return: Fiber | null,        // Parent

  // State
  memoizedState: any,          // Current state (hooks linked list)
  memoizedProps: Object,       // Current props
  pendingProps: Object,        // New props

  // Effects
  effectTag: number,           // What to do (UPDATE, PLACEMENT, DELETION)
  nextEffect: Fiber | null,    // Next fiber with effects

  // DOM
  stateNode: DOMNode | null,   // Actual DOM node

  // Alternate (double buffering)
  alternate: Fiber | null      // Work-in-progress counterpart
}

Key Innovation: Fiber enables incremental rendering—work can be paused, resumed, or abandoned.

4. Reconciliation (Diffing Algorithm)

React’s diffing algorithm compares old and new Virtual DOM trees:

Two Key Heuristics:

  1. Different types → Replace entire subtree
  2. Same type → Update attributes, recurse on children

The Algorithm:

1. Compare root elements
   - Different type? → Unmount old, mount new
   - Same type? → Keep node, update props

2. Recurse on children
   - Without keys: Compare by index (inefficient for lists)
   - With keys: Match by key (efficient reordering)

3. Collect effects (what DOM operations are needed)

Why Keys Matter:

// Without keys - React compares by index
// Inserting at beginning re-renders ALL items
[A, B, C]  [Z, A, B, C]  // React thinks: A→Z, B→A, C→B, +C

// With keys - React matches by identity
[A:a, B:b, C:c]  [Z:z, A:a, B:b, C:c]  // React knows: just insert Z

5. Two-Phase Rendering

React renders in two distinct phases:

Render Phase (Interruptible):

  • Build new Fiber tree (Work-in-Progress)
  • Call component functions / render methods
  • Diff with current tree
  • NO side effects yet (no DOM changes)
  • Can be paused, resumed, or discarded

Commit Phase (Synchronous):

  • Apply all DOM mutations at once
  • Run useLayoutEffect (blocking)
  • Swap current ↔ WIP tree pointers
  • Run useEffect (non-blocking, after paint)
Time →
[---- Render Phase ----][-- Commit --][-- useEffect --]
                         ↑
                    DOM Updated
                    (User sees change)

6. How Hooks Work Internally

Hooks are stored as a linked list on the Fiber node:

// Simplified hooks storage
fiber.memoizedState = {
  // First hook (useState)
  memoizedState: 0,              // Current state value
  queue: { pending: null },       // Update queue
  next: {
    // Second hook (useEffect)
    memoizedState: {
      create: () => {...},        // Effect callback
      destroy: undefined,         // Cleanup function
      deps: [dep1, dep2]          // Dependencies
    },
    next: {
      // Third hook (useRef)
      memoizedState: { current: null },
      next: null
    }
  }
};

Why Order Matters (Rules of Hooks): React identifies hooks by their call order, not by name. The hook index must be consistent across renders:

// ❌ WRONG - conditional hook
if (condition) {
  const [state, setState] = useState(0);  // Index 0 sometimes
}
const [other, setOther] = useState(1);    // Index 0 or 1?

// ✅ CORRECT - consistent order
const [state, setState] = useState(0);    // Always index 0
const [other, setOther] = useState(1);    // Always index 1
if (condition) {
  // use state here
}

7. Synthetic Events

React wraps native browser events in SyntheticEvent objects:

// React doesn't attach handlers to each element
// Instead: one listener at the root (event delegation)

// Before React 17: document level
document.addEventListener('click', handler);

// React 17+: React root level
rootContainer.addEventListener('click', handler);

// When event fires:
1. Native event bubbles to root
2. React finds the target element
3. Creates SyntheticEvent (cross-browser wrapper)
4. Walks up fiber tree, calling matching handlers

Why Synthetic Events?

  • Cross-browser consistency
  • Performance (event delegation = fewer listeners)
  • Event pooling (reuse event objects) - deprecated in React 17
  • Integration with React’s update batching

8. Concurrent Rendering & Time Slicing

React 18 introduced concurrent features powered by the Scheduler:

Time Slicing: Break rendering into 5ms chunks, yield to browser between chunks.

Legacy Mode (blocking):
[=============== 100ms render ===============]
❌ Browser frozen, can't respond to input

Concurrent Mode (time-sliced):
[5ms][5ms][5ms][5ms]...[5ms]
      ↑    ↑    ↑
   Browser can process input between chunks

Priority Levels:

  1. Immediate: User input (typing, clicking)
  2. User-blocking: Hover, scroll
  3. Normal: Data fetching results
  4. Low: Analytics
  5. Idle: Prefetching

Key APIs:

  • useTransition: Mark updates as non-urgent
  • useDeferredValue: Defer expensive re-renders
  • startTransition: Lower priority for wrapped updates

Project List

The following 14 projects will teach you React internals from first principles, culminating in building your own React.


Project 1: Build Your Own createElement

  • File: LEARN_REACT_INTERNALS.md
  • Main Programming Language: JavaScript
  • Alternative Programming Languages: TypeScript
  • Coolness Level: Level 3: Genuinely Clever
  • Business Potential: 1. The “Resume Gold”
  • Difficulty: Level 1: Beginner
  • Knowledge Area: JSX / Virtual DOM / React Elements
  • Software or Tool: Node.js, Babel (optional)
  • Main Book: Build Your Own React (pomb.us)

What you’ll build: A createElement function that transforms JSX-like syntax into a tree of plain JavaScript objects (Virtual DOM).

Why it teaches React internals: This is the entry point to React. Every JSX tag becomes a createElement call. Understanding this shows you that React Elements are just objects—nothing magical.

Core challenges you’ll face:

  • Handling different element types → maps to components vs DOM elements
  • Normalizing children → maps to text nodes, arrays, null
  • Understanding the element structure → maps to type, props, key, ref

Resources for key challenges:

Key Concepts:

  • React Elements: Plain objects describing what to render
  • JSX Transformation: Babel’s role
  • Children Normalization: Handling various child types

Difficulty: Beginner Time estimate: 2-3 days Prerequisites: JavaScript basics, understanding of trees

Real world outcome:

// Your createElement function
function createElement(type, props, ...children) {
  return {
    type,
    props: {
      ...props,
      children: children.map(child =>
        typeof child === 'object' ? child : createTextElement(child)
      )
    }
  };
}

function createTextElement(text) {
  return {
    type: 'TEXT_ELEMENT',
    props: { nodeValue: text, children: [] }
  };
}

// Usage (or via Babel JSX transform)
const element = createElement(
  'div',
  { className: 'container' },
  createElement('h1', null, 'Hello'),
  createElement('p', null, 'World')
);

console.log(element);
// {
//   type: 'div',
//   props: {
//     className: 'container',
//     children: [
//       { type: 'h1', props: { children: [...] } },
//       { type: 'p', props: { children: [...] } }
//     ]
//   }
// }

Implementation Hints:

The key insight is that React Elements are just objects. Nothing more:

// A React Element is just:
{
  type: 'div' | MyComponent,  // String for DOM, function for components
  props: {
    // All attributes
    className: 'container',
    onClick: () => {},
    // Children are also in props
    children: [/* more elements */]
  },
  key: null,   // For reconciliation
  ref: null    // For DOM access
}

Handle edge cases:

  • null and undefined children (skip them)
  • Primitive children (wrap in text element)
  • Array children (flatten)

Learning milestones:

  1. Basic createElement works → You understand element structure
  2. Text nodes handled → You normalize children
  3. Nested elements work → You can build any tree
  4. Configure Babel to use your createElement → Full JSX support

Project 2: Build Your Own Renderer (DOM)

  • File: LEARN_REACT_INTERNALS.md
  • Main Programming Language: JavaScript
  • Alternative Programming Languages: TypeScript
  • Coolness Level: Level 3: Genuinely Clever
  • Business Potential: 1. The “Resume Gold”
  • Difficulty: Level 2: Intermediate
  • Knowledge Area: DOM Manipulation / Rendering
  • Software or Tool: Browser, Node.js
  • Main Book: Build Your Own React (pomb.us)

What you’ll build: A render function that takes a Virtual DOM tree and creates actual DOM nodes, appending them to a container.

Why it teaches React internals: This is ReactDOM’s core job—turning React Elements into real DOM. Understanding this shows you the Virtual DOM → Real DOM translation.

Core challenges you’ll face:

  • Creating DOM elements from virtual nodes → maps to document.createElement
  • Setting props/attributes → maps to attribute handling, event listeners
  • Recursively rendering children → maps to tree traversal
  • Handling text nodes → maps to createTextNode

Key Concepts:

  • DOM APIs: createElement, createTextNode, appendChild
  • Attribute Handling: Properties vs attributes
  • Event Handling: addEventListener

Difficulty: Intermediate Time estimate: 3-4 days Prerequisites: Project 1, DOM API knowledge

Real world outcome:

function render(element, container) {
  // Create DOM node
  const dom =
    element.type === 'TEXT_ELEMENT'
      ? document.createTextNode('')
      : document.createElement(element.type);

  // Set properties
  Object.keys(element.props)
    .filter(key => key !== 'children')
    .forEach(name => {
      if (name.startsWith('on')) {
        const eventType = name.toLowerCase().substring(2);
        dom.addEventListener(eventType, element.props[name]);
      } else {
        dom[name] = element.props[name];
      }
    });

  // Render children recursively
  element.props.children.forEach(child => render(child, dom));

  // Append to container
  container.appendChild(dom);
}

// Usage
const element = createElement(
  'div',
  { className: 'app' },
  createElement('h1', null, 'Hello React!'),
  createElement('button', { onClick: () => alert('Clicked!') }, 'Click me')
);

render(element, document.getElementById('root'));

Implementation Hints:

Property handling has nuances:

// Some properties are different from attributes
if (name === 'className') {
  dom.className = value;
} else if (name === 'style' && typeof value === 'object') {
  Object.assign(dom.style, value);
} else if (name.startsWith('on')) {
  dom.addEventListener(name.slice(2).toLowerCase(), value);
} else {
  dom.setAttribute(name, value);
}

Learning milestones:

  1. Static elements render → Basic DOM creation works
  2. Props are set → Attributes and styles work
  3. Events work → onClick, onChange fire
  4. Children render → Nested structures work

Project 3: Implement the Diffing Algorithm

  • File: LEARN_REACT_INTERNALS.md
  • Main Programming Language: JavaScript
  • Alternative Programming Languages: TypeScript
  • Coolness Level: Level 4: Hardcore Tech Flex
  • Business Potential: 1. The “Resume Gold”
  • Difficulty: Level 3: Advanced
  • Knowledge Area: Algorithms / Tree Comparison
  • Software or Tool: Browser
  • Main Book: React Reconciliation Docs

What you’ll build: A diffing algorithm that compares old and new Virtual DOM trees and generates minimal DOM operations.

Why it teaches React internals: This is the heart of React’s performance. Instead of replacing the entire DOM, React calculates the minimum changes needed.

Core challenges you’ll face:

  • Comparing element types → maps to same type = update, different = replace
  • Diffing props → maps to add, remove, update attributes
  • Diffing children → maps to the key algorithm
  • Generating patches → maps to describing DOM operations

Resources for key challenges:

Key Concepts:

  • Tree Diffing Heuristics: O(n) instead of O(n³)
  • Keys for Children: Efficient list reconciliation
  • Patch Objects: Describing changes

Difficulty: Advanced Time estimate: 1 week Prerequisites: Projects 1-2, algorithm basics

Real world outcome:

function diff(oldNode, newNode) {
  // No new node → Remove
  if (!newNode) {
    return { type: 'REMOVE' };
  }

  // No old node → Add
  if (!oldNode) {
    return { type: 'ADD', newNode };
  }

  // Different types → Replace
  if (oldNode.type !== newNode.type) {
    return { type: 'REPLACE', newNode };
  }

  // Same type → Update props, diff children
  if (typeof oldNode.type === 'string') {
    const propPatches = diffProps(oldNode.props, newNode.props);
    const childPatches = diffChildren(
      oldNode.props.children,
      newNode.props.children
    );

    return { type: 'UPDATE', propPatches, childPatches };
  }
}

// Example usage
const oldTree = createElement('div', { className: 'old' },
  createElement('p', null, 'Hello')
);

const newTree = createElement('div', { className: 'new' },
  createElement('p', null, 'Hello'),
  createElement('p', null, 'World')  // Added
);

const patches = diff(oldTree, newTree);
// { type: 'UPDATE',
//   propPatches: [{ className: 'old' → 'new' }],
//   childPatches: [null, { type: 'ADD', ... }]
// }

Implementation Hints:

The key insight is React’s heuristics:

// Heuristic 1: Different types = completely different trees
// Don't try to match <div> children with <span> children
if (oldNode.type !== newNode.type) {
  return { type: 'REPLACE', newNode };
}

// Heuristic 2: Keys identify children across renders
function diffChildren(oldChildren, newChildren) {
  // Build map of old children by key
  const oldKeyedChildren = {};
  oldChildren.forEach((child, i) => {
    const key = child.props?.key ?? i;
    oldKeyedChildren[key] = { child, index: i };
  });

  // Match new children to old by key
  return newChildren.map((newChild, i) => {
    const key = newChild.props?.key ?? i;
    const old = oldKeyedChildren[key];
    if (old) {
      return diff(old.child, newChild);
    } else {
      return { type: 'ADD', newNode: newChild };
    }
  });
}

Learning milestones:

  1. Type comparison works → Replace when types differ
  2. Prop diffing works → Minimal attribute updates
  3. Child diffing works → Handles additions/removals
  4. Keys work → Efficient list reordering

Project 4: Build Fiber-like Work Units

  • File: LEARN_REACT_INTERNALS.md
  • Main Programming Language: JavaScript
  • Alternative Programming Languages: TypeScript
  • Coolness Level: Level 4: Hardcore Tech Flex
  • Business Potential: 1. The “Resume Gold”
  • Difficulty: Level 3: Advanced
  • Knowledge Area: Fiber Architecture / Incremental Rendering
  • Software or Tool: Browser, requestIdleCallback
  • Main Book: React Fiber Architecture (GitHub)

What you’ll build: A Fiber-like work loop that breaks rendering into units of work, allowing the browser to interrupt and handle user input.

Why it teaches React internals: This is React’s biggest architectural innovation since Virtual DOM. Fiber enables concurrent rendering by making work interruptible.

Core challenges you’ll face:

  • Creating Fiber nodes → maps to work unit structure
  • Building the work loop → maps to requestIdleCallback / scheduler
  • Traversing the tree → maps to child, sibling, return pointers
  • Committing work → maps to two-phase rendering

Resources for key challenges:

Key Concepts:

  • Fiber Node Structure: type, props, state, effects
  • Work Loop: Interruptible rendering
  • Double Buffering: Current tree vs WIP tree

Difficulty: Advanced Time estimate: 1-2 weeks Prerequisites: Projects 1-3

Real world outcome:

// Fiber node structure
function createFiber(element, parent) {
  return {
    type: element.type,
    props: element.props,
    parent,
    child: null,
    sibling: null,
    alternate: null,      // Link to current tree
    effectTag: null,      // UPDATE, PLACEMENT, DELETION
    dom: null             // Actual DOM node
  };
}

// Work loop
let nextUnitOfWork = null;
let wipRoot = null;        // Work-in-progress root
let currentRoot = null;    // Current tree on screen

function workLoop(deadline) {
  let shouldYield = false;

  while (nextUnitOfWork && !shouldYield) {
    nextUnitOfWork = performUnitOfWork(nextUnitOfWork);
    shouldYield = deadline.timeRemaining() < 1;  // Yield if < 1ms left
  }

  // If all work done, commit
  if (!nextUnitOfWork && wipRoot) {
    commitRoot();
  }

  requestIdleCallback(workLoop);
}

requestIdleCallback(workLoop);

// Process one fiber, return next
function performUnitOfWork(fiber) {
  // 1. Create DOM if needed
  if (!fiber.dom) {
    fiber.dom = createDom(fiber);
  }

  // 2. Create fibers for children
  const elements = fiber.props.children;
  let prevSibling = null;

  elements.forEach((element, index) => {
    const newFiber = createFiber(element, fiber);

    if (index === 0) {
      fiber.child = newFiber;
    } else {
      prevSibling.sibling = newFiber;
    }
    prevSibling = newFiber;
  });

  // 3. Return next unit of work
  // First try child, then sibling, then uncle
  if (fiber.child) return fiber.child;

  let nextFiber = fiber;
  while (nextFiber) {
    if (nextFiber.sibling) return nextFiber.sibling;
    nextFiber = nextFiber.parent;
  }

  return null;
}

Implementation Hints:

Tree traversal order:

     A          Traversal: A → B → D → E → C → F
   /   \
  B     C        1. Go to child if exists
 / \     \       2. Else go to sibling
D   E     F      3. Else go to parent's sibling (uncle)

Double buffering:

// Two trees
currentRoot  // What's on screen
wipRoot      // What we're building

// On commit, swap them
function commitRoot() {
  commitWork(wipRoot.child);
  currentRoot = wipRoot;
  wipRoot = null;
}

Learning milestones:

  1. Work loop runs → Fibers process over multiple frames
  2. Tree builds correctly → Child/sibling links work
  3. Can yield to browser → Animation doesn’t stutter
  4. Commit phase works → DOM updates atomically

Project 5: Implement useState Hook

  • File: LEARN_REACT_INTERNALS.md
  • Main Programming Language: JavaScript
  • Alternative Programming Languages: TypeScript
  • Coolness Level: Level 4: Hardcore Tech Flex
  • Business Potential: 1. The “Resume Gold”
  • Difficulty: Level 3: Advanced
  • Knowledge Area: Hooks / State Management
  • Software or Tool: Your mini-React
  • Main Book: Under the Hood of React’s Hooks System

What you’ll build: A working useState hook that persists state across renders and triggers re-renders on updates.

Why it teaches React internals: Hooks seem magical but are surprisingly simple. They’re just arrays/linked lists stored on the Fiber node.

Core challenges you’ll face:

  • Storing state on the fiber → maps to memoizedState
  • Maintaining hook order → maps to Rules of Hooks
  • Triggering re-renders → maps to update queues
  • Handling multiple useState calls → maps to hook index

Resources for key challenges:

Key Concepts:

  • Hook Storage: Linked list on fiber.memoizedState
  • Closure Over State: How setState captures correct value
  • Update Queue: Batching state updates

Difficulty: Advanced Time estimate: 1 week Prerequisites: Project 4 (Fiber)

Real world outcome:

let wipFiber = null;
let hookIndex = null;

function useState(initial) {
  const oldHook = wipFiber.alternate?.hooks?.[hookIndex];

  const hook = {
    state: oldHook ? oldHook.state : initial,
    queue: []
  };

  // Process pending state updates
  const actions = oldHook ? oldHook.queue : [];
  actions.forEach(action => {
    hook.state = typeof action === 'function'
      ? action(hook.state)
      : action;
  });

  const setState = action => {
    hook.queue.push(action);
    // Trigger re-render
    wipRoot = {
      dom: currentRoot.dom,
      props: currentRoot.props,
      alternate: currentRoot
    };
    nextUnitOfWork = wipRoot;
  };

  wipFiber.hooks.push(hook);
  hookIndex++;

  return [hook.state, setState];
}

// Before rendering a functional component
function updateFunctionComponent(fiber) {
  wipFiber = fiber;
  hookIndex = 0;
  wipFiber.hooks = [];

  const children = [fiber.type(fiber.props)];
  reconcileChildren(fiber, children);
}

// Usage
function Counter() {
  const [count, setCount] = useState(0);
  return createElement('button',
    { onClick: () => setCount(c => c + 1) },
    count
  );
}

Implementation Hints:

Why order matters:

// Hooks are identified by call ORDER, not name
function Component() {
  // Call 1 → hooks[0]
  const [name, setName] = useState('');
  // Call 2 → hooks[1]
  const [age, setAge] = useState(0);
  // Call 3 → hooks[2]
  const [email, setEmail] = useState('');
}

// On re-render, hooks[0] must be name, hooks[1] must be age...
// That's why you can't put hooks in conditionals!

Learning milestones:

  1. Initial state works → First render has correct value
  2. setState triggers re-render → Updates cause new render
  3. State persists → Value carries across renders
  4. Multiple useState works → Hook index system works

Project 6: Implement useEffect Hook

  • File: LEARN_REACT_INTERNALS.md
  • Main Programming Language: JavaScript
  • Alternative Programming Languages: TypeScript
  • Coolness Level: Level 4: Hardcore Tech Flex
  • Business Potential: 1. The “Resume Gold”
  • Difficulty: Level 3: Advanced
  • Knowledge Area: Hooks / Side Effects / Lifecycle
  • Software or Tool: Your mini-React
  • Main Book: React useEffect Documentation

What you’ll build: A working useEffect hook that runs side effects after render and supports cleanup and dependencies.

Why it teaches React internals: useEffect unifies componentDidMount, componentDidUpdate, and componentWillUnmount. Understanding its timing model is crucial.

Core challenges you’ll face:

  • Running effects after commit → maps to effect timing
  • Dependency comparison → maps to Object.is shallow compare
  • Cleanup functions → maps to running previous cleanup before new effect
  • Effect scheduling → maps to useEffect vs useLayoutEffect

Key Concepts:

  • Effect Timing: After paint (useEffect) vs before paint (useLayoutEffect)
  • Dependency Array: When to re-run
  • Cleanup Pattern: Return function from effect

Difficulty: Advanced Time estimate: 1 week Prerequisites: Project 5 (useState)

Real world outcome:

function useEffect(callback, deps) {
  const oldHook = wipFiber.alternate?.hooks?.[hookIndex];

  const hasChanged = !oldHook || !deps ||
    deps.some((dep, i) => !Object.is(dep, oldHook.deps[i]));

  const hook = {
    deps,
    effect: hasChanged ? callback : null,
    cleanup: oldHook?.cleanup
  };

  wipFiber.hooks.push(hook);
  hookIndex++;
}

// After commit phase, run effects
function commitRoot() {
  // Run cleanup from previous render
  deletions.forEach(commitWork);

  commitWork(wipRoot.child);

  // Run effects
  runEffects(wipRoot);

  currentRoot = wipRoot;
  wipRoot = null;
}

function runEffects(fiber) {
  if (!fiber) return;

  fiber.hooks?.forEach(hook => {
    // Run previous cleanup
    if (hook.cleanup) hook.cleanup();

    // Run new effect
    if (hook.effect) {
      hook.cleanup = hook.effect();
    }
  });

  runEffects(fiber.child);
  runEffects(fiber.sibling);
}

// Usage
function Timer() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    const id = setInterval(() => setCount(c => c + 1), 1000);
    return () => clearInterval(id);  // Cleanup
  }, []);  // Empty deps = mount only

  return createElement('div', null, count);
}

Implementation Hints:

Effect timing:

Render Phase        Commit Phase        After Paint
[build tree] -----> [update DOM] -----> [run useEffect]
                          ↓
                    [run useLayoutEffect]

Dependency comparison:

function depsChanged(oldDeps, newDeps) {
  if (!oldDeps || !newDeps) return true;
  if (oldDeps.length !== newDeps.length) return true;

  return oldDeps.some((dep, i) => !Object.is(dep, newDeps[i]));
}

Learning milestones:

  1. Effects run after render → Timing is correct
  2. Cleanup runs → Previous effect is cleaned up
  3. Dependencies work → Effect only runs when deps change
  4. Empty deps = mount only → Runs once

Project 7: Implement useRef Hook

  • File: LEARN_REACT_INTERNALS.md
  • Main Programming Language: JavaScript
  • Alternative Programming Languages: TypeScript
  • Coolness Level: Level 2: Practical but Forgettable
  • Business Potential: 1. The “Resume Gold”
  • Difficulty: Level 2: Intermediate
  • Knowledge Area: Hooks / Mutable References
  • Software or Tool: Your mini-React
  • Main Book: React useRef Documentation

What you’ll build: A useRef hook that provides a mutable container persisting across renders without triggering re-renders.

Why it teaches React internals: useRef is the simplest hook—just a stable object. But it reveals how React persists values without reactivity.

Core challenges you’ll face:

  • Creating persistent object → maps to same object across renders
  • Not triggering re-renders → maps to mutations don’t schedule updates
  • Accessing DOM nodes → maps to ref prop handling

Key Concepts:

  • Mutable Container: { current: value }
  • Stable Identity: Same object every render
  • DOM Access: Assigning ref.current = domNode

Difficulty: Intermediate Time estimate: 2-3 days Prerequisites: Project 5 (useState)

Real world outcome:

function useRef(initial) {
  const oldHook = wipFiber.alternate?.hooks?.[hookIndex];

  const hook = oldHook || { current: initial };

  wipFiber.hooks.push(hook);
  hookIndex++;

  return hook;  // Same object every time
}

// Usage
function TextInput() {
  const inputRef = useRef(null);

  const focusInput = () => {
    inputRef.current.focus();
  };

  return createElement('div', null,
    createElement('input', { ref: inputRef }),
    createElement('button', { onClick: focusInput }, 'Focus')
  );
}

Implementation Hints:

Handling ref prop:

// When creating DOM, check for ref
function createDom(fiber) {
  const dom = /* create element */;

  // Assign ref
  if (fiber.props.ref) {
    fiber.props.ref.current = dom;
  }

  return dom;
}

Learning milestones:

  1. useRef returns stable object → Same ref across renders
  2. Mutations don’t re-render → ref.current = x doesn’t trigger update
  3. DOM refs work → Can access actual DOM nodes

Project 8: Implement Event Delegation

  • File: LEARN_REACT_INTERNALS.md
  • Main Programming Language: JavaScript
  • Alternative Programming Languages: TypeScript
  • Coolness Level: Level 3: Genuinely Clever
  • Business Potential: 1. The “Resume Gold”
  • Difficulty: Level 2: Intermediate
  • Knowledge Area: Events / Performance / Delegation
  • Software or Tool: Browser
  • Main Book: React SyntheticEvent Documentation

What you’ll build: An event system that uses delegation (single listener at root) instead of attaching listeners to each element.

Why it teaches React internals: React doesn’t attach onClick to buttons—it uses event delegation for performance and consistency.

Core challenges you’ll face:

  • Single root listener → maps to event delegation pattern
  • Finding the target fiber → maps to mapping DOM to fibers
  • Bubbling through fiber tree → maps to simulating event propagation
  • SyntheticEvent wrapper → maps to cross-browser normalization

Resources for key challenges:

Key Concepts:

  • Event Delegation: One listener catches all
  • Fiber ↔ DOM Mapping: Finding fiber from DOM node
  • Synthetic Events: Normalized event interface

Difficulty: Intermediate Time estimate: 1 week Prerequisites: Project 4 (Fiber)

Real world outcome:

// Store fiber reference on DOM node
function createDom(fiber) {
  const dom = document.createElement(fiber.type);
  dom.__fiber = fiber;  // Link DOM → Fiber
  return dom;
}

// Single listener at root
function setupEventDelegation(root) {
  ['click', 'change', 'input', 'keydown', 'keyup'].forEach(eventType => {
    root.addEventListener(eventType, event => {
      let fiber = event.target.__fiber;

      // Walk up fiber tree, call handlers
      while (fiber) {
        const handler = fiber.props[`on${capitalize(eventType)}`];
        if (handler) {
          // Create synthetic event
          const syntheticEvent = createSyntheticEvent(event);
          handler(syntheticEvent);

          if (syntheticEvent.isPropagationStopped) break;
        }
        fiber = fiber.parent;
      }
    });
  });
}

function createSyntheticEvent(nativeEvent) {
  return {
    nativeEvent,
    target: nativeEvent.target,
    currentTarget: nativeEvent.currentTarget,
    type: nativeEvent.type,
    isPropagationStopped: false,
    stopPropagation() {
      this.isPropagationStopped = true;
      nativeEvent.stopPropagation();
    },
    preventDefault() {
      nativeEvent.preventDefault();
    }
  };
}

Implementation Hints:

Why delegation is better:

// Without delegation: 1000 buttons = 1000 listeners
buttons.forEach(btn => btn.addEventListener('click', handler));

// With delegation: 1000 buttons = 1 listener
root.addEventListener('click', event => {
  // Find which button was clicked
  const fiber = event.target.__fiber;
  if (fiber.props.onClick) fiber.props.onClick(event);
});

Learning milestones:

  1. Root listener catches events → Delegation works
  2. Correct handler called → DOM → Fiber mapping works
  3. Bubbling works → Events propagate up fiber tree
  4. stopPropagation works → Can prevent bubbling

Project 9: Implement Reconciliation with Keys

  • File: LEARN_REACT_INTERNALS.md
  • Main Programming Language: JavaScript
  • Alternative Programming Languages: TypeScript
  • Coolness Level: Level 4: Hardcore Tech Flex
  • Business Potential: 1. The “Resume Gold”
  • Difficulty: Level 3: Advanced
  • Knowledge Area: Reconciliation / Lists / Keys
  • Software or Tool: Your mini-React
  • Main Book: React Reconciliation Documentation

What you’ll build: Enhanced reconciliation that uses keys to efficiently reorder, insert, and delete list items.

Why it teaches React internals: Keys are the most misunderstood React concept. Understanding them requires understanding how reconciliation matches old and new children.

Core challenges you’ll face:

  • Building key → fiber map → maps to O(1) lookup of old children
  • Matching by key → maps to finding corresponding old fiber
  • Detecting moves → maps to reordering optimization
  • Handling index fallback → maps to when no key is provided

Key Concepts:

  • Keys as Identity: Stable identity across renders
  • Map-based Matching: O(n) reconciliation
  • Move vs Replace: Reusing fibers for reordered items

Difficulty: Advanced Time estimate: 1 week Prerequisites: Projects 3-4 (Diffing, Fiber)

Real world outcome:

function reconcileChildren(wipFiber, elements) {
  // Build map of old children by key
  const oldFibers = {};
  let oldFiber = wipFiber.alternate?.child;
  while (oldFiber) {
    const key = oldFiber.props.key ?? oldFiber.index;
    oldFibers[key] = oldFiber;
    oldFiber = oldFiber.sibling;
  }

  let prevSibling = null;

  elements.forEach((element, index) => {
    const key = element.props?.key ?? index;
    const oldFiber = oldFibers[key];
    delete oldFibers[key];  // Mark as used

    let newFiber;

    // Same type = update
    if (oldFiber && oldFiber.type === element.type) {
      newFiber = {
        type: element.type,
        props: element.props,
        dom: oldFiber.dom,       // Reuse DOM!
        parent: wipFiber,
        alternate: oldFiber,
        effectTag: 'UPDATE'
      };
    }
    // Different type = replace
    else {
      newFiber = {
        type: element.type,
        props: element.props,
        dom: null,
        parent: wipFiber,
        alternate: null,
        effectTag: 'PLACEMENT'
      };

      if (oldFiber) {
        oldFiber.effectTag = 'DELETION';
        deletions.push(oldFiber);
      }
    }

    // Link siblings
    if (index === 0) {
      wipFiber.child = newFiber;
    } else {
      prevSibling.sibling = newFiber;
    }
    prevSibling = newFiber;
  });

  // Remaining old fibers are deletions
  Object.values(oldFibers).forEach(fiber => {
    fiber.effectTag = 'DELETION';
    deletions.push(fiber);
  });
}

Implementation Hints:

Why keys help:

// Without keys: [A, B, C] → [C, A, B]
// React compares by index:
// 0: A → C (different, replace)
// 1: B → A (different, replace)
// 2: C → B (different, replace)
// = 3 DOM operations

// With keys: [A:a, B:b, C:c] → [C:c, A:a, B:b]
// React matches by key:
// c: found at index 2, move to 0
// a: found at index 0, move to 1
// b: found at index 1, move to 2
// = 0 DOM recreations, just moves

Learning milestones:

  1. Key matching works → Correct old fiber found
  2. Reordering reuses DOM → No unnecessary recreation
  3. Additions/deletions work → New items added, old removed
  4. Performance improved → List updates are fast

Project 10: Implement Batched Updates

  • File: LEARN_REACT_INTERNALS.md
  • Main Programming Language: JavaScript
  • Alternative Programming Languages: TypeScript
  • Coolness Level: Level 3: Genuinely Clever
  • Business Potential: 1. The “Resume Gold”
  • Difficulty: Level 2: Intermediate
  • Knowledge Area: Performance / Update Batching
  • Software or Tool: Your mini-React
  • Main Book: React 18 Automatic Batching

What you’ll build: Update batching that combines multiple setState calls into a single re-render.

Why it teaches React internals: Without batching, setState + setState = 2 renders. React batches them into 1 render for performance.

Core challenges you’ll face:

  • Collecting updates → maps to queue of pending updates
  • Scheduling a single render → maps to microtask or setTimeout
  • Flushing at the right time → maps to event handler boundaries

Key Concepts:

  • Update Queue: Collecting setState calls
  • Scheduling: When to flush updates
  • Automatic Batching: React 18’s improvement

Difficulty: Intermediate Time estimate: 3-4 days Prerequisites: Project 5 (useState)

Real world outcome:

let isBatchingUpdates = false;
let pendingUpdates = [];

function scheduleUpdate(fiber) {
  pendingUpdates.push(fiber);

  if (!isBatchingUpdates) {
    isBatchingUpdates = true;

    // Use microtask for automatic batching
    queueMicrotask(() => {
      flushUpdates();
      isBatchingUpdates = false;
    });
  }
}

function flushUpdates() {
  // Start render from root
  wipRoot = {
    dom: currentRoot.dom,
    props: currentRoot.props,
    alternate: currentRoot
  };
  nextUnitOfWork = wipRoot;
  pendingUpdates = [];
}

// Usage
function Counter() {
  const [count, setCount] = useState(0);
  const [flag, setFlag] = useState(false);

  const handleClick = () => {
    setCount(c => c + 1);  // Queued
    setFlag(f => !f);       // Queued
    // Only ONE re-render happens!
  };

  console.log('Render');  // Logs once per click
  return createElement('button', { onClick: handleClick }, count);
}

Implementation Hints:

React 18 automatic batching:

// React 17: Only batched in event handlers
onClick={() => {
  setA(1);  // Batched
  setB(2);  // Batched
});

setTimeout(() => {
  setA(1);  // NOT batched (React 17)
  setB(2);  // NOT batched (React 17)
});

// React 18: Batched EVERYWHERE automatically
setTimeout(() => {
  setA(1);  // Batched!
  setB(2);  // Batched!
});

Learning milestones:

  1. Multiple setStates = 1 render → Batching works
  2. Works in event handlers → Sync updates batched
  3. Works in setTimeout → Async updates batched
  4. Correct final state → All updates applied

Project 11: Implement Context (useContext)

  • File: LEARN_REACT_INTERNALS.md
  • Main Programming Language: JavaScript
  • Alternative Programming Languages: TypeScript
  • Coolness Level: Level 3: Genuinely Clever
  • Business Potential: 1. The “Resume Gold”
  • Difficulty: Level 2: Intermediate
  • Knowledge Area: State Management / Context
  • Software or Tool: Your mini-React
  • Main Book: React Context Documentation

What you’ll build: A Context system with createContext, Provider, and useContext for sharing state without prop drilling.

Why it teaches React internals: Context is React’s built-in state sharing. Understanding how values flow down the tree reveals React’s rendering model.

Core challenges you’ll face:

  • Creating context object → maps to Provider + Consumer + default value
  • Provider component → maps to wrapping children with value
  • Walking up tree for value → maps to finding nearest Provider
  • Re-rendering consumers → maps to when context value changes

Key Concepts:

  • Provider/Consumer Pattern: Component-based value distribution
  • Tree Walking: Finding nearest provider
  • Subscription: Updating when context changes

Difficulty: Intermediate Time estimate: 1 week Prerequisites: Project 5 (useState)

Real world outcome:

function createContext(defaultValue) {
  const context = {
    _currentValue: defaultValue,
    Provider: null,
    Consumer: null
  };

  context.Provider = function Provider({ value, children }) {
    context._currentValue = value;
    return children;
  };

  return context;
}

function useContext(context) {
  // In real React, this walks up the fiber tree
  // to find the nearest Provider
  return context._currentValue;
}

// Usage
const ThemeContext = createContext('light');

function App() {
  const [theme, setTheme] = useState('dark');

  return createElement(ThemeContext.Provider, { value: theme },
    createElement(Toolbar, null),
    createElement('button',
      { onClick: () => setTheme(t => t === 'dark' ? 'light' : 'dark') },
      'Toggle'
    )
  );
}

function Toolbar() {
  return createElement(ThemedButton, null);
}

function ThemedButton() {
  const theme = useContext(ThemeContext);
  return createElement('button', { className: theme }, 'I am themed');
}

Implementation Hints:

Real implementation walks fiber tree:

function useContext(context) {
  let fiber = wipFiber;

  // Walk up looking for Provider
  while (fiber) {
    if (fiber.type === context.Provider) {
      return fiber.props.value;
    }
    fiber = fiber.parent;
  }

  // No provider found, use default
  return context._defaultValue;
}

Learning milestones:

  1. createContext works → Returns Provider + default
  2. useContext reads value → Gets current context value
  3. Nested providers work → Inner value overrides outer
  4. Updates propagate → Context change re-renders consumers

Project 12: Implement Concurrent Features (Basic)

  • File: LEARN_REACT_INTERNALS.md
  • Main Programming Language: JavaScript
  • Alternative Programming Languages: TypeScript
  • Coolness Level: Level 5: Pure Magic (Super Cool)
  • Business Potential: 1. The “Resume Gold”
  • Difficulty: Level 4: Expert
  • Knowledge Area: Concurrent Rendering / Scheduling
  • Software or Tool: Your mini-React
  • Main Book: React 18 Concurrent Features

What you’ll build: Basic concurrent features—time slicing with priority and a simplified useTransition hook.

Why it teaches React internals: Concurrent rendering is React’s most advanced feature. Understanding it shows you how React keeps apps responsive during heavy work.

Core challenges you’ll face:

  • Time slicing → maps to yielding to browser between work
  • Priority levels → maps to urgent vs non-urgent updates
  • Interruptible rendering → maps to discarding stale work
  • useTransition → maps to marking updates as low priority

Resources for key challenges:

Key Concepts:

  • Time Slicing: 5ms work chunks
  • Priority Lanes: Urgent vs deferred updates
  • Transitions: Non-blocking updates

Difficulty: Expert Time estimate: 2 weeks Prerequisites: Projects 4-6 (Fiber, hooks)

Real world outcome:

// Priority levels
const ImmediatePriority = 1;
const UserBlockingPriority = 2;
const NormalPriority = 3;
const LowPriority = 4;
const IdlePriority = 5;

let currentPriority = NormalPriority;

function scheduleCallback(priority, callback) {
  const task = { priority, callback };
  taskQueue.push(task);
  taskQueue.sort((a, b) => a.priority - b.priority);

  if (!isScheduled) {
    isScheduled = true;
    requestIdleCallback(workLoop);
  }
}

function workLoop(deadline) {
  while (taskQueue.length > 0 && deadline.timeRemaining() > 1) {
    const task = taskQueue.shift();
    task.callback();
  }

  if (taskQueue.length > 0) {
    requestIdleCallback(workLoop);
  } else {
    isScheduled = false;
  }
}

// useTransition marks updates as non-urgent
function useTransition() {
  const [isPending, setIsPending] = useState(false);

  const startTransition = callback => {
    setIsPending(true);
    scheduleCallback(LowPriority, () => {
      callback();
      setIsPending(false);
    });
  };

  return [isPending, startTransition];
}

// Usage
function Search() {
  const [query, setQuery] = useState('');
  const [results, setResults] = useState([]);
  const [isPending, startTransition] = useTransition();

  const handleChange = e => {
    // Urgent: update input immediately
    setQuery(e.target.value);

    // Non-urgent: update results later
    startTransition(() => {
      setResults(search(e.target.value));
    });
  };

  return createElement('div', null,
    createElement('input', { value: query, onChange: handleChange }),
    isPending ? 'Loading...' : results.map(r => createElement('div', null, r))
  );
}

Implementation Hints:

Time slicing in work loop:

function workLoopConcurrent() {
  while (nextUnitOfWork && !shouldYield()) {
    nextUnitOfWork = performUnitOfWork(nextUnitOfWork);
  }
}

function shouldYield() {
  // Yield after 5ms of work
  return performance.now() - workStartTime > 5;
}

Learning milestones:

  1. Time slicing works → UI stays responsive during render
  2. Priority works → Urgent updates happen first
  3. useTransition works → Non-blocking state updates
  4. isPending works → Can show loading state

Project 13: Read React Source Code

  • File: LEARN_REACT_INTERNALS.md
  • Main Programming Language: JavaScript (reading)
  • Alternative Programming Languages: N/A
  • Coolness Level: Level 5: Pure Magic (Super Cool)
  • Business Potential: 1. The “Resume Gold”
  • Difficulty: Level 4: Expert
  • Knowledge Area: Source Code Analysis
  • Software or Tool: React source, IDE
  • Main Book: React Source Code

What you’ll build: A documented deep-dive into React’s actual source code, tracing key code paths and understanding real implementation details.

Why it teaches React internals: You’ve built simplified versions—now see how the React team does it. Their code is well-organized and teachable.

Core challenges you’ll face:

  • Navigating monorepo → maps to understanding package structure
  • Tracing execution → maps to following function calls
  • Understanding optimizations → maps to why certain patterns are used
  • Reading Flow types → maps to type annotations in React source

Key Concepts:

  • Monorepo Structure: packages/react, packages/react-dom, etc.
  • Scheduler Package: Priority and time slicing
  • Reconciler Package: Fiber and rendering

Difficulty: Expert Time estimate: 2-4 weeks Prerequisites: All previous projects

Real world outcome:

# My React Source Code Study

## Package Structure
- packages/react - createElement, hooks, context
- packages/react-dom - DOM rendering, event system
- packages/react-reconciler - Fiber, reconciliation (shared)
- packages/scheduler - Priority scheduling

## Key Files

### packages/react-reconciler/src/ReactFiber.js
- createFiber() - Creates fiber nodes
- FiberNode class with all the fields I implemented

### packages/react-reconciler/src/ReactFiberWorkLoop.js
- workLoopSync() - Legacy mode rendering
- workLoopConcurrent() - Concurrent rendering with shouldYield

### packages/react-reconciler/src/ReactFiberHooks.js
- renderWithHooks() - Sets up hooks for a component
- useState implementation uses useReducer internally!

## Key Insight: useState is useReducer

function useState(initialState) {
  return useReducer(basicStateReducer, initialState);
}

function basicStateReducer(state, action) {
  return typeof action === 'function' ? action(state) : action;
}

Implementation Hints:

Files to study:

  1. packages/react/src/ReactElement.js - createElement
  2. packages/react-reconciler/src/ReactFiber.js - Fiber structure
  3. packages/react-reconciler/src/ReactFiberHooks.js - Hooks
  4. packages/react-reconciler/src/ReactFiberWorkLoop.js - Render loop
  5. packages/scheduler/src/forks/Scheduler.js - Scheduling

Learning milestones:

  1. Navigate the source → Find what you’re looking for
  2. Trace a render → Follow createElement to DOM update
  3. Trace a hook → Follow useState from call to re-render
  4. Understand real optimizations → Why React does things certain ways

Project 14: Build Complete Mini-React

  • File: LEARN_REACT_INTERNALS.md
  • Main Programming Language: JavaScript/TypeScript
  • Alternative Programming Languages: N/A
  • Coolness Level: Level 5: Pure Magic (Super Cool)
  • Business Potential: 1. The “Resume Gold”
  • Difficulty: Level 5: Master
  • Knowledge Area: Complete Framework
  • Software or Tool: Node.js, Browser
  • Main Book: Build Your Own React (pomb.us)

What you’ll build: A complete mini-React combining all previous projects—createElement, Fiber, reconciliation, hooks, events, and concurrent features.

Why it’s the ultimate capstone: Building a working React from scratch proves you understand React at the deepest level.

Time estimate: 1-2 months Prerequisites: All previous projects

Real world outcome:

// Your mini-React in action
import { createElement, render, useState, useEffect, useRef } from './mini-react';

function App() {
  const [count, setCount] = useState(0);
  const [items, setItems] = useState(['A', 'B', 'C']);
  const inputRef = useRef(null);

  useEffect(() => {
    console.log(`Count is now ${count}`);
  }, [count]);

  return createElement('div', { className: 'app' },
    createElement('h1', null, `Count: ${count}`),
    createElement('button', { onClick: () => setCount(c => c + 1) }, '+'),
    createElement('button', { onClick: () => setCount(c => c - 1) }, '-'),

    createElement('input', { ref: inputRef }),
    createElement('button', { onClick: () => inputRef.current.focus() }, 'Focus'),

    createElement('ul', null,
      items.map((item, i) =>
        createElement('li', { key: item },
          item,
          createElement('button', {
            onClick: () => setItems(items.filter((_, j) => j !== i))
          }, 'x')
        )
      )
    ),
    createElement('button', {
      onClick: () => setItems([...items, String.fromCharCode(65 + items.length)])
    }, 'Add Item')
  );
}

render(createElement(App), document.getElementById('root'));

Learning milestones:

  1. Basic rendering works → Static elements appear
  2. State works → useState triggers re-renders
  3. Effects work → useEffect runs after render
  4. Lists with keys work → Efficient reconciliation
  5. Events work → Event delegation handles clicks
  6. Everything together → Complete React-like experience

Project Comparison Table

Project Difficulty Time Key Concept Fun Factor
1. createElement 2-3 days JSX/Elements ⭐⭐⭐
2. DOM Renderer ⭐⭐ 3-4 days Rendering ⭐⭐⭐
3. Diffing Algorithm ⭐⭐⭐ 1 week Reconciliation ⭐⭐⭐⭐
4. Fiber Work Loop ⭐⭐⭐ 1-2 weeks Fiber Architecture ⭐⭐⭐⭐⭐
5. useState ⭐⭐⭐ 1 week Hooks ⭐⭐⭐⭐⭐
6. useEffect ⭐⭐⭐ 1 week Effects/Lifecycle ⭐⭐⭐⭐
7. useRef ⭐⭐ 2-3 days Mutable Refs ⭐⭐⭐
8. Event Delegation ⭐⭐ 1 week Events ⭐⭐⭐⭐
9. Keys Reconciliation ⭐⭐⭐ 1 week List Rendering ⭐⭐⭐⭐
10. Batched Updates ⭐⭐ 3-4 days Performance ⭐⭐⭐
11. Context ⭐⭐ 1 week State Sharing ⭐⭐⭐
12. Concurrent Features ⭐⭐⭐⭐ 2 weeks Concurrent Mode ⭐⭐⭐⭐⭐
13. Source Code Study ⭐⭐⭐⭐ 2-4 weeks Real Implementation ⭐⭐⭐⭐
14. Complete Mini-React ⭐⭐⭐⭐⭐ 1-2 months Everything ⭐⭐⭐⭐⭐

Phase 1: Foundations (2-3 weeks)

Understand the basic building blocks:

  1. Project 1: createElement - Virtual DOM elements
  2. Project 2: DOM Renderer - Elements to real DOM
  3. Project 3: Diffing Algorithm - Minimal updates

Phase 2: Fiber Architecture (2-3 weeks)

Understand incremental rendering:

  1. Project 4: Fiber Work Loop - Interruptible rendering
  2. Project 8: Event Delegation - How events work
  3. Project 9: Keys Reconciliation - Efficient lists

Phase 3: Hooks (2-3 weeks)

Understand state and effects:

  1. Project 5: useState - State management
  2. Project 6: useEffect - Side effects
  3. Project 7: useRef - Mutable references
  4. Project 11: Context - State sharing

Phase 4: Advanced Features (2-3 weeks)

Understand performance optimizations:

  1. Project 10: Batched Updates - Update coalescing
  2. Project 12: Concurrent Features - Time slicing

Phase 5: Mastery (4-6 weeks)

Deep understanding:

  1. Project 13: Source Code Study - Read real React
  2. Project 14: Complete Mini-React - Build it all

Summary

# Project Main Language
1 Build Your Own createElement JavaScript
2 Build Your Own Renderer JavaScript
3 Implement Diffing Algorithm JavaScript
4 Build Fiber Work Loop JavaScript
5 Implement useState JavaScript
6 Implement useEffect JavaScript
7 Implement useRef JavaScript
8 Implement Event Delegation JavaScript
9 Implement Keys Reconciliation JavaScript
10 Implement Batched Updates JavaScript
11 Implement Context JavaScript
12 Implement Concurrent Features JavaScript
13 Read React Source Code JavaScript
14 Build Complete Mini-React JavaScript

Resources

Essential Tutorials

Architecture Deep Dives

Hooks Internals

Official Documentation

Source Code

  • React GitHub - Official source
  • Key directories: packages/react, packages/react-reconciler, packages/scheduler

Total Estimated Time: 4-6 months of dedicated study

After completion: You’ll understand React at the level of its creators. You’ll debug any React issue instantly, write highly performant code naturally, and be able to contribute to React itself or build your own UI library.