Effects
An effect runs code whenever the signals it reads change.
Basic Usage
import { signal, effect, path } from 'sairin';
const count = signal(path("counter"), 0);
effect(() => {
console.log("Count is:", count.get());
});
count.set(1); // Logs: "Count is: 1"
count.set(2); // Logs: "Count is: 2"
Scheduling Tiers
Sairin has three scheduling tiers:
| Tier | API | When it Runs | Use Case |
|---|---|---|---|
| Sync | effectSync() |
Immediately | Critical path |
| Micro | effect() |
Next microtask | Default - DOM updates |
| Idle | effectIdle() |
requestIdleCallback |
Analytics, logging |
import { effect, effectSync, effectIdle } from 'sairin';
effectSync(() => {
console.log("Sync!");
});
effect(() => {
console.log("Microtask");
});
effectIdle(() => {
console.log("Idle time");
});
Cleanup Functions
Effects can return a cleanup function:
const count = signal(path("counter"), 0);
effect(() => {
const current = count.get();
console.log("Count:", current);
return () => {
console.log("Cleaning up!");
};
});
count.set(1); // Logs: "Count: 1", then registers cleanup
count.set(2); // Runs cleanup, then logs: "Count: 2"
onCleanup
Register cleanup without returning from the effect:
import { effect, onCleanup } from 'sairin';
effect(() => {
const timer = setTimeout(() => console.log("Done!"), 1000);
onCleanup(() => clearTimeout(timer));
});
Disposing Effects
const count = signal(path("counter"), 0);
const dispose = effect(() => {
console.log("Count:", count.get());
});
count.set(1); // Logs: "Count: 1"
count.set(2); // Logs: "Count: 2"
dispose(); // Effect is removed
count.set(3); // Nothing, effect is gone
Untracked Reads
Read without subscribing:
import { signal, effect, untracked, path } from 'sairin';
const a = signal(path("a"), 1);
const b = signal(path("b"), 2);
effect(() => {
console.log(a.get(), untracked(() => b.get()));
});
a.set(10); // Effect runs
b.set(20); // Effect does NOT run (untracked)