Reactivity
AkashJS uses a fine-grained reactivity system based on signals. Signals are reactive values that automatically track dependencies and update only what changed — no virtual DOM diffing needed.
signal()
A signal holds a reactive value. Read it by calling it as a function. Write it with .set() or .update().
import { signal } from '@akashjs/runtime';
const count = signal(0);
count(); // 0 (read)
count.set(5); // write
count.update(c => c + 1); // update from previous
count.peek(); // read without trackingcomputed()
A computed signal derives from other signals. It recomputes lazily when dependencies change.
import { signal, computed } from '@akashjs/runtime';
const count = signal(2);
const doubled = computed(() => count() * 2);
doubled(); // 4
count.set(5);
doubled(); // 10Computed signals are read-only — you cannot call .set() on them.
effect()
An effect runs a side-effect whenever its tracked signals change.
import { signal, effect } from '@akashjs/runtime';
const name = signal('Alice');
const dispose = effect(() => {
console.log(`Hello, ${name()}`);
});
// Logs: "Hello, Alice"
name.set('Bob');
// Logs: "Hello, Bob"
dispose(); // Stop watchingEffects can return a cleanup function:
effect(() => {
const handler = () => console.log(count());
window.addEventListener('click', handler);
return () => window.removeEventListener('click', handler);
});batch()
Batch multiple signal updates to avoid intermediate re-computations:
import { signal, batch } from '@akashjs/runtime';
const first = signal('Alice');
const last = signal('Smith');
batch(() => {
first.set('Bob');
last.set('Jones');
// Effects run once after the batch, not twice
});untrack()
Read a signal without registering a dependency:
import { signal, computed, untrack } from '@akashjs/runtime';
const a = signal(1);
const b = signal(2);
const sum = computed(() => a() + untrack(() => b()));
// Only re-runs when `a` changes, not when `b` changeson()
Create an effect that only tracks specific signals. All other signal reads inside the callback are untracked.
import { effect, on } from '@akashjs/runtime';
// Only re-runs when url changes, not when options changes
effect(on(url, (currentUrl, prevUrl) => {
fetch(currentUrl, options()); // options() not tracked
}));
// Multiple signals
effect(on([url, page], ([currentUrl, currentPage]) => {
fetch(`${currentUrl}?page=${currentPage}`);
}));
// Run immediately (by default, on() skips the initial run)
effect(on(url, (val) => console.log(val), { defer: false }));How It Works
- When a signal is read inside a
computed()oreffect(), it registers a dependency. - When a signal is written, it notifies all subscribers.
- Computed signals re-evaluate lazily — only when read.
- Effects are scheduled on the microtask queue for batching.
- No virtual DOM — signal changes directly patch the specific DOM node.