Version v2.2.1 Size 2.6 KB gzip Dependencies Zero dependencies
Why Ripple?
Hand-rolled reactive state spreads subscription, cleanup, and derived-value rules across application code. Ripple gives you one graph boundary with explicit disposal and fine-grained dependencies while keeping rendering and routing outside the runtime.
ts
// Before
let count = 0;
const listeners = new Set<() => void>();
function setCount(next: number) {
count = next;
for (const listener of listeners) listener();
}
// After
import { createRipple } from '@vielzeug/ripple';
const ripple = createRipple();
const count = ripple.signal(0);
const doubled = ripple.computed(() => count.value * 2);
const stop = ripple.effect(() => console.log(doubled.value));
count.value = 1;
stop.dispose();
ripple.dispose();| Feature | Ripple | Zustand | Jotai |
|---|---|---|---|
| Bundle size | 2.6 KB | ~3.5 kB | ~7 kB |
| Zero dependencies | |||
| Framework-agnostic | React-first | ||
| Explicit graph lifetime | |||
| Fine-grained derived values | Selectors | Atoms |
Use Ripple when you need framework-independent state with explicit graph lifetime and small composable primitives.
Consider a framework store when component bindings, server cache, or framework-specific tooling matter more than portable reactive state.
Installation
sh
pnpm add @vielzeug/ripplesh
npm install @vielzeug/ripplesh
yarn add @vielzeug/rippleQuick Start
Create one graph, derive a value, observe it, then dispose resources when the graph lifetime ends.
ts
import { createRipple } from '@vielzeug/ripple';
const ripple = createRipple();
const count = ripple.signal(0);
const doubled = ripple.computed(() => count.value * 2);
const stop = ripple.effect(() => console.log(doubled.value));
ripple.batch(() => {
count.value = 1;
count.value = 2;
});
stop.dispose();
ripple.dispose();Features
createRipple()creates an isolated graph and lifetime boundary.signal()stores writable values with configurable equality.computed()derives lazy read-only values.effect()reacts to dependency changes with cleanup support.batch()coalesces synchronous writes and notifications.createScope()groups owned reactive work.watch()observes one selected source transition.resource()loads async values with stale-work cancellation.