Reactive

All-around state engine with signals and fine-grained updates.

One small package for every kind of state. A signal stores a value. A derived value follows it. A record gives state a shape. A reducer gives every change an action. All of them share one subscription model, so learning one teaches you the rest.

Framework agnostic, typed end to end, and small enough to use for a single field.

Start Here

Core Ideas

  • Fine-grained updates. Subscribers hear about a value only when that value changes.
  • Two signal styles. Event based and closure based, used together in the same app.
  • Explicit state shapes. Arrays, maps, booleans, finite state machines, reducers and records.
  • Action-driven changes. Put writes behind dispatch or an @action method when a value has rules.
  • Batching built in. Group writes and notify once with the final values.
  • Lazy derivations. A derived value attaches to its source only while someone observes it.

Quick Peek

import { State, StateArray } from "@denshya/reactive"

const blog = {
  articles: new StateArray([{ title: "Hello" }]),
  user: new State({ name: "me" })
}

blog.articles.subscribe(articles => console.log(articles))
blog.user.$.name.subscribe(name => console.log(name))

blog.articles.push({ title: "Second post" })
blog.user.$.name.set("you")
import { StateReducer, StateRecord, local, action } from "@denshya/reactive"

const counter = StateReducer.fromHandlers<number, { type: "increment" }>(0, {
  increment: state => state + 1
})

class Settings extends StateRecord {
  @local accessor theme = "light"

  @action toggleTheme() {
    this.theme = this.theme === "light" ? "dark" : "light"
  }
}

Install

bun add @denshya/reactive
npm install @denshya/reactive

License

MIT