Skip to content

seatedro/act

Repository files navigation

act: A Minimal React Implementation

This repository contains a minimal implementation of React's core functionalities, demonstrated through a simple Counter component. The implementation shows how React's reconciliation, fiber architecture, and state management work under the hood.

Usage

  1. Clone the repository:

    git clone git@github:com:seatedro/act.git
  2. Bundle the code:

    bun build App.tsx index.ts --out-dir dist
  3. Serve the index.html file:

    bunx serve .

Overview

The implementation focuses on three main aspects:

  1. Component rendering and re-rendering
  2. State management (useState hook)
  3. Reconciliation process

Core Concepts

Fiber Architecture

  • Each UI element is represented by a Fiber node
  • Fibers form a tree structure matching the component hierarchy
  • Each Fiber contains:
    {
      type: string | function,
      dom: Node | null,
      props: Object,
      parent: Fiber,
      sibling: Fiber,
      alternate: Fiber,
      effectTag: "UPDATE" | "PLACEMENT" | "DELETION"
    }

State Management

function useState(initial) {
  const hook = {
    state: oldHook ? oldHook.state : initial,
    queue: []  // for pending updates
  };
  // Process queued updates
  const actions = oldHook ? oldHook.queue : [];
  actions.forEach(action => {
    hook.state = action(hook.state);
  });
  return [hook.state, setState];
}

Reconciliation Process

The process of determining what has changed and needs updating:

  1. Initial Render:
// Everything is marked as PLACEMENT
{
  elementType: "div",
  sameType: null,
  effectTag: "PLACEMENT"
}
  1. Updates:
// Elements are compared and marked as UPDATE
{
  elementType: "div",
  oldFiberType: "div",
  sameType: true,
  effectTag: "UPDATE"
}

Implementation Details

Counter Component

function Counter() {
  const [count, setCount] = useState(0);
  return (
    <div>
      <h1>{count}</h1>
      <button onClick={() => setCount(c => c + 1)}>+</button>
    </div>
  );
}

Render Pipeline

  1. Initial Render:
Component Mount → useState Setup → Reconcile Children → Create DOM
  1. State Update:
Button Click → setState → Queue Update → Create WIP Root → Re-render → Reconcile → Update DOM

Debugging Output

Here's what happens during a typical update cycle:

  1. Initial Render:
[useState] { hookIndex: 0, currentState: 0, queuedActions: 0 }
[Component Render] Count: 0
[reconcileChildren Step] {
  elementType: "div",
  sameType: null,
  effectTag: "PLACEMENT"  // Everything is new
}
  1. After Button Click:
[setState Triggered] {
  action: "(c) => c + 1",
  newWipRoot: { /* ... */ }
}
[useState] { hookIndex: 0, currentState: 1, queuedActions: 0 }
[Component Render] Count: 1
[reconcileChildren Step] {
  elementType: "div",
  oldFiberType: "div",
  sameType: true,
  effectTag: "UPDATE"  // Structure unchanged, just update
}

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published