npm.io
0.2.0 • Published yesterday

@j13b/state

Licence
Apache-2.0
Version
0.2.0
Deps
0
Size
409 kB
Vulns
0
Weekly
0

@j13b/state

Framework-agnostic reactive state primitives for TypeScript — Signals, Runners, and broadcast subscriptions.

Install

npm install @j13b/state

This package has no dependencies and works anywhere TypeScript runs — Node, workers, the browser, any framework. Using React? @j13b/react-state provides hooks (useSignalValue, useRunnerStatus, …) built on these primitives.

Quick start

import { Signal } from "@j13b/state";

const counter = new Signal(0);

const subscription = counter.subscribe((value) => {
  console.log("counter is now", value);
});

counter.set(1); // logs: counter is now 1
counter.set(2); // logs: counter is now 2

subscription.unsubscribe();

Entry points

Both entry points are React-free and export the same primitives:

Import path Use when
@j13b/state The default — everything the package offers.
@j13b/state/core You want an explicit "core primitives" import path; alias of the root.
import { Signal, Runner } from "@j13b/state";
// or, equivalently
import { Signal, Runner } from "@j13b/state/core";

React hooks live in the companion package @j13b/react-state.

What's in the box

  • Signal<T> — reactive value with weakly-held subscriptions, set / transform / wait / waitFor.
  • DerivedSignal — values computed from one or more upstream signals.
  • Runner — async-task lifecycle abstraction with status broadcasting.
  • Broadcast / Subscription — the underlying interfaces that signals and runners implement.
  • EventsEvent, AsyncEvent, BaseEvent for fire-and-forget messaging.
  • HelpersPollAsync, WeakPromise, delay.

Subscription lifecycle

Subscriptions are tracked via WeakRef — if you don't keep a reference to the returned subscription, the garbage collector will eventually drop it and your callback will stop firing. Always store the subscription (in a variable, instance field, or hook ref) for as long as you want to receive updates.

// Wrong — subscription gets GC'd, callback stops working
counter.subscribe((v) => console.log(v));

// Right — held by `sub`, lives until you unsubscribe
const sub = counter.subscribe((v) => console.log(v));
sub.unsubscribe();

Scripts

npm run build         # vite + dts → dist/
npm run check:types   # tsc --noEmit
npm test              # vitest watch
npm run test:run      # vitest run (CI)

Origins

This package is a fork of @tcn/state (Copyright 2024 TCN). See NOTICE for upstream attribution.

License

Apache License 2.0 — see LICENSE.

Keywords