Signals & Effects
Rivet ships a tiny, synchronous reactive system: signals hold values, effects react to changes, computed derives values. Dependencies are tracked automatically — no manual subscribing.
Signals
Section titled “Signals”A signal is a container for a value. Reading happens by calling it, writing via
set / update.
const count = signal(0);
count(); // read — subscribes the surrounding effectcount.peek(); // read WITHOUT subscribingcount.set(1); // writecount.update((v) => v + 1); // transform| Call | Effect |
|---|---|
count() | Reads the value. Inside an effect the dependency is registered. |
count.peek() | Reads the value without subscribing. |
count.set(v) | Sets the value and notifies subscribers. |
count.update(fn) | Sets fn(current). |
Effects
Section titled “Effects”An effect runs immediately and again whenever a signal read inside it changes.
effect(() => { // Every signal read here becomes a dependency. output.textContent = String(count());});Cleanup inside an effect
Section titled “Cleanup inside an effect”If the effect returns a function, it is called before the next run and on disposal — ideal for timers, observers or subscriptions.
effect(() => { const id = setInterval(() => tick(), 1000); return () => clearInterval(id); // cleanup before next run / on dispose});Computed
Section titled “Computed”computed derives a value from other signals. It updates automatically when a
dependency changes.
const price = signal(10);const qty = signal(3);const total = computed(() => price() * qty());
total(); // 30qty.set(4);total(); // 40Internally computed(fn) is a signal fed by an effect — it is itself a signal
again and can be read in further effects/computeds.
batch bundles multiple writes so dependent effects run once at the end
instead of after every set.
import { batch } from "@fullhaus/rivet";
batch(() => { price.set(20); qty.set(5);}); // effects that read price & qty run exactly onceuntrack
Section titled “untrack”untrack reads signals without subscribing the surrounding effect — useful
when an effect should react to one signal but only “read along” another.
import { untrack } from "@fullhaus/rivet";
effect(() => { // Reacts to `qty`, but NOT to `price`: const snapshot = untrack(() => price()) * qty(); render(snapshot);});Mental model
Section titled “Mental model”- Reading a signal → inside an effect = subscribe.
- Signal
set→ re-run all dependent effects (synchronously, unlessbatch). Object.isequality prevents unnecessary runs.- Effects optionally return a cleanup function.