Skip to content

Reactivity (API)

The reactive functions are available both as top-level exports from @fullhaus/rivet and (partly) on the component context.

import { signal, computed, effect, batch, untrack } from "@fullhaus/rivet";
function signal<T>(initial: T): SignalGetter<T>;

Creates a reactive signal with an initial value.

type SignalGetter<T> = {
(): T; // read (subscribes the effect)
set(value: T): void; // write; no-op on Object.is equality
update(fn: (current: T) => T): void; // transform
peek(): T; // read without subscribing
};
CallEffect
s()Reads the value; inside an effect the dependency is registered.
s.set(v)Sets the value. Ignored if Object.is(old, new).
s.update(f)Sets f(current).
s.peek()Reads the value without subscribing.
function computed<T>(fn: () => T): SignalGetter<T>;

Derived signal that updates as soon as a dependency read in fn changes. The result is itself a SignalGetter<T>.

const total = computed(() => price() * qty());
type EffectFn = () => void | (() => void);
function effect(fn: EffectFn): Dispose;

Runs fn immediately and again on changes of signals read inside. If fn returns a function, it runs before the next run and on dispose as cleanup.

const stop = effect(() => {
const id = setInterval(tick, 1000);
return () => clearInterval(id);
});
stop(); // stop the effect + run the last cleanup
function batch(fn: () => void): void;

Bundles writes: dependent effects run once at the end of fn instead of after every individual set.

batch(() => {
price.set(20);
qty.set(5);
}); // one re-run instead of two
function untrack<T>(fn: () => T): T;

Runs fn without the signals read inside subscribing the surrounding effect.

effect(() => {
const snapshot = untrack(() => config()); // does NOT react to config
render(data(), snapshot);
});
type Dispose = (() => void) & Disposable;

A Dispose is callable and implements Symbol.dispose, so it works with using:

{
using stop = effect(() => { /* … */ });
} // stopped automatically
  • Reading inside an effect = subscribe; peek/untrack do not subscribe.
  • set with an Object.is-equal value is a no-op.
  • Updates are synchronous unless bundled in batch.
  • Effects and computeds release resources via cleanup return / dispose.