-
Notifications
You must be signed in to change notification settings - Fork 0
cristiAndreiTarasi/echojs
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Β | Β | |||
Β | Β | |||
Β | Β | |||
Β | Β | |||
Repository files navigation
# Echojs π **Echojs** is a lightweight, vanilla JavaScript reactive framework for building highly responsive DOM applications with minimal abstraction and no virtual DOM. --- ## π¦ Usage Example The example project implements a reactive Todo app using all Echojs core features. --- ## π§ Public API Below are all the publicly used methods and contracts in this app: ### π§ Reactivity Engine #### `createState(obj, { deep = true })` Creates a reactive proxy from a plain object or array. - If `deep: true`, nested objects are recursively proxied. - If `deep: false`, creates a shallow reactive state (used for local state). ```js const state = createState({ todos: [] }); // deeply reactive ``` --- #### `effect(fn)` Registers a reactive computation. Re-runs `fn` when any tracked dependency changes. ```js const stop = effect(() => { console.log(state.todos.length); }); ``` - Automatically tracks reads to reactive properties inside `fn`. - Returns a disposable effect object: ```js effect().dispose(); ``` --- #### `batch(fn)` Executes updates inside `fn` in a single batch. Delays reactive effects until `fn` completes. ```js batch(() => { state.count++; state.flag = true; }); ``` --- ### π§© Local State #### `createLocalState(key, initial)` Creates or retrieves a shallow component-scoped reactive state associated with a unique key. ```js const localState = createLocalState(item.id, { count: 0 }); ``` > Use this to store ephemeral UI state like counters, toggles, or animation flags. --- #### `disposeLocalState(key)` Removes ephemeral state associated with a key. Used during DOM unmounting. ```js disposeLocalState(item.id); ``` --- ### β»οΈ Lifecycle Management #### `registerDisposal(domNode, disposeFn)` Registers a function to be called when the node is removed from the DOM. ```js registerDisposal(li, () => { effect.dispose(); disposeLocalState(item.id); }); ``` > Ensures memory safety and untracked state. --- ### π List Management #### `mountList(container, items, getKey, renderItem)` Mounts and updates a list of reactive items into a container. ```js const unmount = mountList( document.getElementById('todoList'), state.todos, item => item.id, createTodoItem ); ``` - Diffs the item list using `getKey(item)` - Mounts new items using `renderItem(item)` - Disposes and removes unmounted nodes - Returns an `unmount()` function to clean up everything manually --- ## π Reactivity Rules & Gotchas ### β Reactive Mutation Rules > π« Do **not** mutate reactive arrays directly with `push`, `splice`, etc. > > β Instead, **replace** the array reference to trigger reactivity: ```js // β Doesn't trigger reactivity state.todos.push({ id: 1, text: 'Oops' }); // β Triggers reactivity state.todos = [...state.todos, { id: 1, text: 'Works!' }]; ``` ### π Why? Echojs tracks the **reference** of reactive state (e.g. `state.todos`). Mutating the internal array does not change the reference, so effects wonβt re-run. > Even though Echojs has a custom `ReactiveArray` with `trigger()` support, you must *reassign* to trigger top-level effects. --- ### π§Ό Disposal Is Manual Echojs does not use a virtual DOM. You **must** call `registerDisposal()` and clean up per-node effects or local state to avoid memory leaks. --- ## β Best Practices - Always `disposeEffect()` and `disposeLocalState()` when unmounting - Wrap multiple updates in `batch()` to avoid redundant re-renders - Use `createLocalState()` for ephemeral per-component state - Use `mountList()` for dynamic lists that respond to changes --- ## π Project Structure ``` . βββ echojs/ β βββ lifecycle.js # Disposal system β βββ list.js # mountList logic β βββ local.js # createLocalState & cleanup β βββ reactivity.js # Core reactivity engine β βββ state.js # Reactive proxies and ReactiveArray βββ main.js # Application logic βββ index.html # DOM container ``` --- ## π Credits Inspired by concepts from: - Vue's fine-grained reactivity - SolidJS's local state and disposal - Svelte's reactive assignment rules --- ## π§ͺ Todo App Demo Implemented features: - Reactive global todo list (`state.todos`) - Local per-item state for counters - Disposal of local state and effects - Dynamic list rendering with diffing - Immutable updates with `state.todos = [...]` --- ## π Conclusion Echojs gives you the tools to build a fast, small, and understandable reactive UI system β **without frameworks**. But with great power comes great responsibility: manage state immutably, and clean up effects diligently. Happy hacking! π§ π§
About
No description, website, or topics provided.
Resources
Stars
Watchers
Forks
Releases
No releases published
Packages 0
No packages published