Reactive Core
Signals#
TC39-aligned, glitch-free diamond propagation, custom equality
Computed#
lazy, cached, version-tracked
Effects#
auto-tracking, auto-cleanup via scopes, optional cleanup callback (return () => …)
untrack()#
read signals without subscribing
linked()#
writable derived that resets when its source changes; persisted() — a signal in localStorage/sessionStorage with cross-tab sync; selector() — O(2) updates for "selected row"; until() — await a signal (until(ready), until(n).toBe(3), { timeout })
provide() / inject()#
context down the scope chain and across islands via DOM ancestors
watch()#
onCleanup, { once }, pause() / resume(); computed((prev) => …, { initial })
Batch#
group updates, single flush
Reactive objects#
deep Proxy-based reactivity (like Vue reactive()), arrays included: push/splice/sort, index writes, length, key add/delete
Store#
definition-based reactive container (properties → signals, getters → computeds, methods → actions, auto-batched)
Interop#
from() turns an EventTarget, a producer or any { subscribe } (Preact, RxJS, Svelte store) into a signal; history() gives undo/redo for a signal, reactive() or store()
reactive() 2.0#
getters become computeds, methods become batched actions, $patch / $subscribe / $snapshot / $reset; only plain objects and arrays are wrapped (Date/Map/File stay as they are); store() = reactive(obj, { shallow: true })
watch()#
explicit dependency watching with debounce
Semantics#
A computed() is subscribed to its sources only while something observes it and needs no scope; what an effect creates in its body dies before the effect re-runs (Solid / Svelte 5 semantics); the setup ctx helpers survive an await. An exception inside computed() is a cached value, not a torn graph: subscriptions survive and the graph recovers as soon as a dependency changes; effect errors go to scope.onError → onError(fn) → reportError, never to the code that wrote the signal.