Skip to content

Navigation Menu

Sign in
Sign up

Latest commit

History

34 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

Custom MiniReact JavaScript Framework

Overview

A lightweight, React-inspired JavaScript framework built from scratch without using any existing libraries or frameworks. This framework implements core frontend concepts including Virtual DOM, component-based architecture, state management with hooks, and client-side routing. The project demonstrates a deep understanding of how modern JavaScript frameworks work under the hood.

Table of Contents

Features

🎨 Virtual DOM Implementation

  • Efficient Diffing Algorithm: Smart DOM reconciliation that updates only what changed
  • Fragment Support: Render multiple elements without wrapper nodes
  • Keyed Elements: Optimized list rendering with key-based reconciliation
  • Text Node Optimization: Efficient handling of text content updates

🪝 React-like Hooks System

  • useState: Manage component state with automatic re-rendering
  • useEffect: Handle side effects with dependency tracking and cleanup
  • useRef: Create mutable references that persist across renders

🧩 Component Architecture

  • Functional Components: Pure functions that return virtual DOM nodes
  • Props System: Pass data and callbacks between components
  • Conditional Rendering: Dynamic UI based on application state
  • List Rendering: Efficiently render dynamic lists with proper key handling

🛣️ Client-Side Routing

  • Hash-based Navigation: URL synchronization with application state
  • Route Handling: Navigate between views without page reloads
  • History Integration: Browser back/forward button support

⚡ Performance Optimizations

  • Minimal DOM Manipulation: Only update changed elements
  • Batched Updates: Group state changes for efficient rendering
  • Effect Scheduling: Run effects asynchronously to avoid blocking

Architecture

The framework follows a unidirectional data flow pattern similar to React:

User Action → State Update → Virtual DOM Creation → Diffing → DOM Update

Core Modules

src/
├── core/
│ ├── vdom.js # Virtual DOM creation and rendering
│ ├── diffing.js # Reconciliation algorithm
│ └── hooks.js # State management hooks
└── index.js # Public API exports

Getting Started

Basic Usage

import { render, createElement, useState } from './src/index.js';
function Counter() {
 const [count, setCount] = useState(0);
 return {
 tag: 'div',
 attrs: {},
 children: [
 {
 tag: 'h1',
 attrs: {},
 children: [`Count: ${count}`]
 },
 {
 tag: 'button',
 attrs: {
 onClick: () => setCount(count + 1)
 },
 children: ['Increment']
 }
 ]
 };
}
// Mount the app
render(Counter, document.getElementById('app'));

Running the TodoMVC Demo

# Navigate to the TodoMVC directory
cd todoMVC
# Open index.html in your browser
# Or use a local server (recommended)
python -m http.server 8000
# Navigate to http://localhost:8000

Core Concepts

1. Virtual DOM Structure

The framework represents UI as JavaScript objects:

// HTML: <div class="container"><h1>Hello</h1></div>
// Virtual DOM representation:
{
 tag: 'div',
 attrs: { class: 'container' },
 children: [
 {
 tag: 'h1',
 attrs: {},
 children: ['Hello']
 }
 ]
}

2. Creating Elements

// Simple element
{
 tag: 'button',
 attrs: {
 class: 'btn',
 onClick: handleClick
 },
 children: ['Click me']
}
// Nested elements
{
 tag: 'ul',
 attrs: { class: 'list' },
 children: [
 { tag: 'li', attrs: {}, children: ['Item 1'] },
 { tag: 'li', attrs: {}, children: ['Item 2'] }
 ]
}

3. Event Handling

Events are attached using camelCase attribute names:

{
 tag: 'input',
 attrs: {
 type: 'text',
 onKeyDown: (e) => {
 if (e.key === 'Enter') {
 console.log('Enter pressed!');
 }
 },
 onChange: (e) => console.log(e.target.value)
 },
 children: []
}

4. Conditional Rendering

Use JavaScript expressions to conditionally render elements:

function Component({ isLoggedIn }) {
 return {
 tag: 'div',
 attrs: {},
 children: [
 isLoggedIn ? {
 tag: 'p',
 attrs: {},
 children: ['Welcome back!']
 } : {
 tag: 'p',
 attrs: {},
 children: ['Please log in']
 }
 ]
 };
}

5. List Rendering with Keys

For dynamic lists, use the key attribute for optimal performance:

function TodoList({ todos }) {
 return {
 tag: 'ul',
 attrs: {},
 children: todos.map(todo => ({
 tag: 'li',
 attrs: {
 key: todo.id // Important for efficient updates
 },
 children: [todo.text]
 }))
 };
}

API Reference

render(component, container)

Mounts the root component to a DOM element.

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

Parameters:

  • component: Function that returns a virtual DOM node
  • container: DOM element to mount the app

useState(initialValue)

Creates a stateful value that triggers re-renders when updated.

const [count, setCount] = useState(0);
// Update state
setCount(count + 1);
// Functional update
setCount(prevCount => prevCount + 1);

Returns: Array with current state and setter function


useEffect(callback, dependencies)

Runs side effects after render. Cleanup functions are called before re-running or unmounting.

// Run on every render
useEffect(() => {
 console.log('Component rendered');
});
// Run once on mount
useEffect(() => {
 console.log('Component mounted');
}, []);
// Run when dependencies change
useEffect(() => {
 console.log('Count changed:', count);
}, [count]);
// With cleanup
useEffect(() => {
 const timer = setInterval(() => console.log('tick'), 1000);
 return () => clearInterval(timer); // Cleanup
}, []);

Parameters:

  • callback: Function to run (can return cleanup function)
  • dependencies: Array of values to watch (optional)

useRef(initialValue)

Creates a mutable reference that persists across renders.

const inputRef = useRef(null);
// Access the ref
useEffect(() => {
 inputRef.current.focus();
}, []);
return {
 tag: 'input',
 attrs: { ref: inputRef },
 children: []
};

Returns: Object with current property


unmount()

Unmounts the current app and cleans up effects.

import { unmount } from './src/index.js';
unmount();

TodoMVC Demo

The framework includes a fully functional TodoMVC implementation showcasing:

  • ✅ Add, edit, and delete todos
  • ✅ Mark todos as complete/incomplete
  • ✅ Filter todos (All, Active, Completed)
  • ✅ Clear completed todos
  • ✅ Toggle all todos
  • ✅ Persistent todo count
  • ✅ URL routing with hash-based navigation
  • ✅ Double-click to edit functionality
  • ✅ Keyboard shortcuts (Enter to save)

TodoMVC Structure

todoMVC/
├── app.js # Main application logic
├── components/
│ ├── todoHeader.js # Input for new todos
│ ├── todoList.js # List of todos with items
│ └── todoFooter.js # Filter buttons and counters
├── index.html # Entry point
└── styles.css # TodoMVC styles

What I Learned

This project provided deep insights into frontend framework internals:

Framework Architecture

  • Virtual DOM Implementation: Built a complete diffing algorithm that efficiently updates the real DOM
  • Reconciliation: Implemented keyed reconciliation for optimal list rendering performance
  • Component Lifecycle: Created a system for mounting, updating, and unmounting components

Advanced JavaScript

  • Closures: Leveraged closures for hook state management and effect tracking
  • Event Delegation: Implemented efficient event handling without memory leaks
  • Algorithm Design: Developed diffing algorithms to minimize DOM operations
  • Module System: Organized code with ES6 modules and clean separation of concerns

State Management

  • Hook Implementation: Built useState, useEffect, and useRef from scratch
  • Dependency Tracking: Implemented dependency arrays for effect optimization
  • Batch Updates: Grouped state changes to prevent unnecessary re-renders
  • Effect Cleanup: Managed side effect lifecycle and cleanup functions

DOM Manipulation

  • Performance Optimization: Minimized reflows and repaints through smart diffing
  • Fragment Handling: Implemented fragment rendering for cleaner component trees
  • Attribute Management: Built efficient attribute updating without full replacement
  • Text Node Optimization: Optimized text content updates

Routing & Navigation

  • Hash-based Routing: Implemented client-side navigation with URL synchronization
  • State-URL Sync: Kept application state in sync with browser URL
  • History API: Integrated with browser history for back/forward navigation

Software Design Principles

  • Inversion of Control: Understood the framework-vs-library distinction
  • API Design: Created intuitive, React-like APIs for developers
  • Documentation: Wrote comprehensive documentation for framework users
  • Testing: Debugged complex asynchronous rendering and state updates

Problem Solving

  • Edge Cases: Handled conditional rendering, null values, and nested fragments
  • Performance: Optimized rendering for large lists with proper key handling
  • Memory Management: Prevented memory leaks in event handlers and effects
  • Browser Compatibility: Ensured cross-browser DOM manipulation

Technologies

  • Language: Vanilla JavaScript (ES6+)
  • Module System: ES6 Modules
  • DOM API: Native browser APIs
  • No External Dependencies: Built entirely from scratch

Technical Highlights

Diffing Algorithm Features

  • Minimal DOM operations through smart reconciliation
  • Support for keyed lists for optimal performance
  • Fragment support for cleaner component trees
  • Efficient text node updates
  • Proper cleanup of removed elements

Hook System Features

  • State persistence across renders
  • Effect dependency tracking
  • Cleanup function support
  • Multiple hooks per component
  • Predictable execution order

Routing Features

  • Hash-based URL routing
  • State synchronization with URL
  • Browser history integration
  • Programmatic navigation support

Why This Approach?

This framework uses Virtual DOM with Diffing because:

  1. Performance: Only updates changed parts of the DOM
  2. Declarative: Developers describe what the UI should look like, not how to change it
  3. Predictable: Unidirectional data flow makes debugging easier
  4. Familiar: API similar to React makes it approachable

Alternative approaches considered:

  • Data Binding: Two-way synchronization (Angular-style)
  • Template Literals: String-based templating
  • Direct DOM: Imperative manipulation

Virtual DOM offered the best balance of performance, developer experience, and maintainability.

About

A React-inspired JavaScript framework built from scratch without using any existing libraries or frameworks. This framework implements core frontend concepts including Virtual DOM, component-based architecture, state management with hooks, and client-side routing.

Topics

Resources

Stars

1 star

Watchers

1 watching

Forks

Contributors

Languages

AltStyle によって変換されたページ (->オリジナル) /