Reactive state for JavaScript

State that updates in quanta.

Write a value and only the code that read it runs โ€” once. Typed stores, async action state, request-scoped containers and persistence in a framework-free core, with official React bindings and no runtime dependencies.

Try it

Press a button. See what re-renders.

Each readout is a React component reading one value with useQuantaValue from the React bindings. The store on the right is the one running it: the action you press lights up, and so does the code that re-ran because it read a value that changed. Nothing else runs.

live store
counts => s.countre-renders 0
doubleds => s.doubledre-renders 0
steps => s.stepre-renders 0

Each readout subscribes to one value. Press a control and watch which ones re-render.

demo-store.tsx
import { defineStore } from '@quantajs/core';import { useQuantaValue, useQuantaActions } from '@quantajs/react'; const useDemo = defineStore('demo', { state: () => ({ count: 7, step: 1 }), getters: { doubled: (s) => s.count * 2, }, actions: { increment() { this.count = (this.count + this.step) % 1000; }, cycleStep() { this.step = this.step === 1 ? 2 : this.step === 2 ? 5 : 1; }, incrementThrice() { // three writes, one action: subscribers wake once this.increment(); this.increment(); this.increment(); }, },}); function Count() { // re-renders only when count changes const count = useQuantaValue(useDemo, (s) => s.count); return <DotMatrix text={String(count)} />;}

the action re-ran: it read a changed valueReact integration

Built in

What you would otherwise assemble yourself.

user-store.ts
const useUser = defineStore('user', { state: () => ({ name: '' }), actions: { async load(id: string) { const res = await fetch(`/api/users/${id}`, { signal: this.$signal, }); this.name = (await res.json()).name; }, },}); const user = useUser();user.load.pending; // true while the request is in flightuser.load.error; // the rejection, or nulluser.load.abort(); // cancels it through $signal
Read the guide

runtime dependencies in @quantajs/core

KB gzip for a store and the React hooks

re-render per action, however many writes it makes

Start with one store.