What Is This?
I built a custom React library from scratch called Didact, reimplementing all the core internals of React — without using React itself. The goal was to deeply understand how React works under the hood by building each subsystem step by step. I followed Build Your Own React by Rodrigo Pombo as a reference for the implementation.
The final result is a mini React runtime capable of rendering real JSX components with stateful useState hooks, event handling, and efficient DOM diffing — all in under ~200 lines of JavaScript across 8 focused modules.
Tech Stack
- Vanilla JavaScript (ES Modules) — zero runtime dependencies
- JSX — transpiled via Babel
- Webpack 5 — bundling and dev server
- requestIdleCallback — for concurrent rendering
Key Concepts Implemented
Virtual DOM & createElement
Converts JSX into a plain JavaScript virtual DOM tree. Text nodes are wrapped in a special TEXT_ELEMENT type for uniform handling.
Fiber Architecture
Each element is represented as a fiber — a linked structure with child, sibling, and parent pointers. This allows the work loop to pause and resume traversal at any point, enabling concurrent rendering.
Concurrent Work Loop
Instead of rendering the entire tree synchronously (which blocks the browser), the engine uses requestIdleCallback to break work into small units — processing one fiber at a time and yielding back to the browser when idle time runs low.
Two-Phase Rendering
DOM mutations are never applied mid-render. All work is collected on a work-in-progress (WIP) root, and only once the entire tree is processed does commitRoot() flush all changes to the real DOM in one pass. This prevents partially rendered UI.
Reconciliation (Diffing)
The diffing algorithm compares the current fiber tree against the new one, child by child:
- Same type → tag as
UPDATE - New element → tag as
PLACEMENT - Removed → tag as
DELETION
This is the core of how React avoids unnecessary DOM operations.
Function Components & Hooks
Function components are detected and executed to get their children. The useState hook maintains state across re-renders by looking up the previous fiber's hooks array. Calling setState queues an action and triggers a full re-render.
The Result
A working counter component with state management — indistinguishable from real React at the usage level:
/** @jsx Didact.createElement */
function Counter() {
const [state, setState] = Didact.useState(1);
return <h1 onClick={() => setState((c) => c + 1)}>Count: {state}</h1>;
}
const element = <Counter />;
const container = document.getElementById("root");
Didact.render(element, container);
What I Learned
Building React from scratch gave me deep insight into fiber trees, concurrent scheduling, two-phase commit rendering, and how hooks actually maintain state across re-renders. It transformed React from a "magic black box" into a well-understood system.