Lifecycle & Cleanup
Rivet cleans up after itself. Every listener, effect, event subscription and
manual cleanup registered on the context is called on unmount — no dangling
timers, no leaks.
mount()
Section titled “mount()”mount(root?) scans root (default: document) for [data-rivet] and
instantiates every not-yet-mounted component.
const app = createRivet().component("counter", counter);
app.mount(); // entire documentapp.mount(container); // only inside an elementmount() is idempotent: already-mounted elements are skipped. You can call
it again after dynamically loading HTML to pick up new roots.
unmount()
Section titled “unmount()”unmount() disposes all instances of the app and calls their collected
cleanups. IDs are released.
app.unmount();What happens automatically on unmount:
on(...)listeners are removed viaremoveEventListenereffect(...)andcomputed(...)are stopped (incl. their effect cleanups)listen(...)/global.listen(...)are unsubscribed- every function registered with
cleanup(fn)runs
Manual cleanup
Section titled “Manual cleanup”For your own resources (observers, timers, external subscriptions) register a
cleanup function via cleanup:
defineComponent(({ root, cleanup }) => { const observer = new IntersectionObserver(/* … */); observer.observe(root);
cleanup(() => observer.disconnect());
return {};});Alternatively, an effect can return its cleanup function — it runs in addition before each re-run of the effect:
effect(() => { const id = setInterval(tick, 1000); return () => clearInterval(id);});Disposable pattern
Section titled “Disposable pattern”The app implements Symbol.dispose. With the using statement (TypeScript 5.2+,
node >= 24 / modern runtimes) it is disposed automatically at the end of the
block:
{ using app = createRivet().component("counter", counter); app.mount(); // … work …} // app[Symbol.dispose]() → unmount() runs automaticallyThe top-level effect export also returns a Dispose (callable and
Symbol.dispose-capable):
import { effect } from "@fullhaus/rivet";
const stop = effect(() => { /* … */ });stop(); // stop manuallyRe-mount after content change
Section titled “Re-mount after content change”Typical pattern with dynamically loaded HTML (e.g. AJAX navigation in TYPO3):
async function loadInto(container: HTMLElement, url: string) { container.innerHTML = await fetch(url).then((r) => r.text()); app.mount(container); // pick up new [data-rivet] roots}