-
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