A lightweight reimplementation of React's core ideas with a virtual DOM, a custom renderer, JSX createElement, reconciliation, and hooks.
Built from scratch to understand how React works internally and to explore tradeoffs in my own implementation.
- Virtual DOM nodes with
tags,props, andchildren - Text node handling via
createTextElement - Functional components with props and children
- Reconciliation for create, delete, tag swap, and update
- Keyed list reconciliation support
- DOM prop updates with attribute diffs
- Hooks with per render call order indexing
- Effects and cleanup with dependency tracking
useStateuseEffectuseRefuseMemouseCallbackuseReduceruseLayoutEffect
| Export | Description |
|---|---|
createElement |
JSX factory for virtual DOM nodes. |
render |
Render a virtual node into a container. |
setRootComponent |
Set root component and trigger rerender. |
useState |
Local state with rerender on update. |
useEffect |
Effect after paint with optional cleanup. |
useRef |
Stable ref object with current. |
useMemo |
Memoized computed value. |
useCallback |
Memoized function reference. |
useReducer |
State with reducer dispatch. |
useLayoutEffect |
Effect after DOM update before paint. |
- Start a local server in the repo root:
python3 -m http.server 8000-
Open
http://localhost:8000and loadindex.htmlor use a sample. -
Import in your JSX file:
import ReactLite, { useState, useEffect, useRef, setRootComponent } from './ReactLite.js';- Mount your app:
setRootComponent(App, document.querySelector('#root'));ReactLite.jsis the core implementation.concept-examples/contains standalone hook and reconciliation demos.article-checkpoints/mirrors the tutorial progression with runnable examples.
For article-checkpoints, open any index.html file directly in a browser. The JSX is compiled in the browser via Babel.
Virtual DOM Representation
Each virtual node is an object with tags, props, and children. Text nodes use createTextElement so reconciliation can treat every node the same way.
Functional Components
If createElement receives a function tag, it calls that function with props and children and returns its output.
Reconciliation Algorithm
The reconciler handles new nodes, deletions, tag changes, and updates for matching tags. It stores a reference to the real DOM node at reactElement.dom to avoid real DOM traversal.
Hooks via Global State Hooks use arrays indexed by call order, which is why hooks must be called consistently each render. Indices reset at the start of a render cycle.
Effect Cleanup Effects can return cleanup functions. Cleanup runs before the next effect with changed deps and on unmount paths.
- Component unmount lifecycle improvements
- Better error handling and dev diagnostics
This is a learning focused implementation, so several core React features are not included:
- No Fiber architecture or concurrent rendering
- No class components or lifecycle methods (will add this eventually)
- No server rendering or hydration
- etc (many more I'm missing)