Reactivity
Reactive primitives are introduced as needed through a clean and abstracted API. It currently leverages a customized version of the SolidJS Core, refactored to classes.
# Reactive Functions
| name | arguments | returns | description |
|---|---|---|---|
| signal | (initialValue?, { equals?: false | (a, b) => boolean }) | [read, write, update] & { read, write, update } | creates a signal. The return value doubles as a tuple ([read, write, update]) and an object ({ read, write, update }), so destructure whichever form you prefer. read() returns the current value; write(next) assigns a new value and returns true when it changed. update(fn) calls fn(prev) without tracking and writes the returned value — prefer it over write whenever the new value depends on the old, so you don't re-read the signal (and don't track the read). Pass equals: false to notify on every write (even when the value is the same), or a custom comparator. |
| memo | fn | signal | read-only signal that will update when the return value of the function changes, memos are lazy |
| derived | (...fn) | signal | lazy, writable version of memo that unwraps and tracks functions and promises recursively. The function won't run unless the result is read; writing to the returned signal overrides the computed value. |
| externalSignal | (initialValue, options?) | signal | signal tailored for arrays of objects with an id key. Writing patches by id, preserving references for items that are unchanged. Useful for syncing server data without introducing a store. |
| root | (dispose => ...) | return value of fn | creates a new top-level tracking scope. The callback receives a dispose function that tears down everything created inside. Reactive work that outlives a component (long-lived subscriptions, imperative rendering) belongs in a root. |
| effect | fn | void | runs fn once immediately, then again whenever any signal it reads changes. Effects are scheduled — they may run later in the microtask queue; use syncEffect if you need synchronous execution. |
| on | (depend, fn) | void | effect with explicit dependencies. Only depend is tracked; fn runs untracked each time depend changes. Handy when the handler reads other signals you don't want as dependencies. |
| syncEffect | fn | void | like effect, but runs synchronously whenever a dependency changes instead of being queued for the next scheduler tick. Use when you need the side effect to land before the current call returns. |
| asyncEffect | (previous: Promise<any> | undefined) => any | void | effect for async work, serialised by default. On each run the callback receives the promise from the previous run (or undefined on the first run); await it to ensure the previous async run finishes before starting new work. |
| listener | () | current listener | undefined | returns the currently-running reactive listener (the tracking scope an inner computation is inside), or undefined if there is none. Useful for introspection. |
| untrack | fn | return value of fn | runs fn without establishing reactive dependencies on anything it reads |
| batch | fn | return value of fn | groups writes so dependents re-run once at the end of fn instead of after each individual write. |
| action | (...cbs) | function | builds an action handler. Returns a function that, when called, runs cbs[0] with the received args and chains the remaining callbacks as continuations, unwrapping any returned functions or promises recursively. Cancels automatically if the owner is disposed — handy for async event handlers. |
| catchError | (fn, onError) | return value of fn | undefined | runs fn inside an error boundary. If it throws (synchronously or via a reactive dependency), onError(err) is called and the error does not bubble. Returns the value of fn, or undefined if it threw. |
| cleanup | fn | fn | registers fn to run when the current reactive scope is disposed. Returns the same function so you can keep a reference. Callbacks run in reverse-registration order (LIFO). |
| owned | (fn, onCancel?) | function | captures the current owner and returns a function bound to it. Calling that function re-runs fn under the captured owner, as long as the owner hasn't been disposed. If the owner is disposed before the function is called, onCancel runs instead. Useful for scheduling work (timers, promises, events) that must not outlive the component that scheduled it. |
| withValue | (value, fn) | void | resolves value and calls fn(resolved). Functions are unwrapped inside an effect (so fn re-runs on change); promises and arrays of functions/promises are resolved recursively. Plain values call fn immediately. |
| isResolved | (...deriveds) | boolean | true once every passed derived has resolved at least once. Useful with Suspense to know when async-driven derived values are ready. |
| map | (iterable, callback, noSort?, fallback?, reactiveIndex?) | rendered output | reactive equivalent of array.map. Tracks an iterable (array, set, map, signal returning one) and only re-runs callback for added/removed/changed entries — existing rows keep their state. Powers the <For/> component. |