@whxcctv/easy-react
v1.0.6
Published
A lightweight, educational re-implementation of React with hooks, virtual DOM, diffing, context, memo, and reducers.
Maintainers
Readme
Easy React
Easy React is a fully working, lightweight re-implementation of React's core ideas — including virtual DOM, function components, hooks, diffing, patching, context, memo, and reducers.
It preserves the fundamental mental model of React while keeping the code extremely small, readable, and ideal for learning or experimenting with framework design.
✨ Features
✔ JSX-like Virtual DOM
createElement() builder
VElement + TextVNode
Props diffing (including events)
Children diffing (simplified)
✔ Function Components with Persistent State
Supports:
useState
useEffect
useRef
useMemo
useCallback
useReducer
✔ Component Instance Patching (State Preservation)
Components persist between renders
Component.patch() intelligently reuses the previous instance
Internal state, effects, and refs remain stable across updates
✔ Effect Scheduling
Effects run after DOM mount/update using queueMicrotask
Dependency comparison and cleanup support
✔ Context API (Subscription Model)
createContext
useContext automatically subscribes/unsubscribes
✔ memo() HOC
- Prevents rerendering via customizable props comparison
📦 Installation
Easy React is a single-file library. Simply include it in your project:
import React from '@whxcctv/easy-react';
const { createElement } = React;If you use JSX:
/** @jsx React.createElement */🚀 Quick Start
import React, { useState } from '@whxcctv/easy-react';
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<h1>{count}</h1>
<button onClick={() => setCount(count + 1)}>+1</button>
</div>
);
}
document.body.appendChild(
React.createElement(Counter).render()
);🧠 Architecture Overview
Component Instance ├─ fn (function component) ├─ props ├─ states[] ← useState ├─ effects[] ← useEffect ├─ memos[] ← useMemo / useCallback ├─ child ← last rendered VNode ├─ render() ← execute fn + diff └─ patch() ← reuse instance on parent updates
🔍 Core Design Concepts
1. Virtual DOM: VElement & TextVNode
VElement
Responsible for creating real DOM nodes
Prop diffing:
Event listeners
Attributes and properties
Children diff (simple index-based)
TextVNode
- Efficient text update through nodeValue patching
2. Component: The Hook Dispatcher
Easy React uses a single global pointer:
let CURRENT_COMPONENT = null;Whenever a function component executes, it becomes the current component:
CURRENT_COMPONENT = this;
vnode = this.fn(this.props);This makes all hooks extremely simple:
seState
Persistent state stored in states[] with linear index:
const idx = comp.stateIndex++;
if (comp.states[idx] === undefined) comp.states[idx] = initial;seEffect
Dependency comparison + cleanup + post-DOM scheduling.
seRef
Mutable object persisted across renders.
seMemo / useCallback
Dependency-based memo cache inside the component instance.
3. Diff & Patch system
VElement.patch(newVNode)
Replace if tag changes
Otherwise reuse DOM and diff props
Diff children sequentially
Component.patch(newVNode)
Preserve component instance
Only update props
Re-execute render() to diff children
Keeps all hook states stable, matching React behavior
This is one of the most elegant parts of your design.
4. Context API
Easy React uses a simple publish-subscribe model:
context.subscribers.add(callback)When updates:
- All subscribers (components using the context) refresh
This is similar to React's internal behavior prior to Fiber optimizations.
5. useReducer
Minimal but powerful reducer model:
Internal context object stores state
dispatch triggers refresh
Async reducers supported
📌 Limitations (Compared to React)
Easy React is intentionally small and educational:
Children diff is index-based (no keyed diff yet)
No Fiber architecture
No concurrent mode
No Suspense / lazy (can be added later)
Fragment is simplified (rendered as a wrapper)
No DevTools integration (yet)
Despite these, it is more than enough for learning and experimentation.
🔮 Possible Future Improvements
If you want to extend the project, here are natural next steps:
Full keyed diff algorithm
Real Fragments
Suspense + lazy
Porting to a Fiber tree architecture
Scheduler based on requestIdleCallback
DevTools inspector overlay
Renderers (e.g., React-DOM, React-Native)
I can help you implement any of these if you'd like.
❤️ Acknowledgements
This project is inspired by React and Preact, but aims to be:
inimal
ransparent
ducational
ackable
It demonstrates the complete mental model of React in a tiny amount of code — ideal for understanding how frameworks work internally, or for designing your own.
