npm install @watchable/store
# for optional features
npm install @watchable/store-react # React binding
npm install @watchable/store-follow # Business-logic binding
npm install @watchable/store-edit # Immer drafts
A @watchable/store
Store
maintains a immutably-typed reference to an (array or object) state
with
intuitive utilities for wiring up ui components and business logic.
See the Medium article
import { createStore } from "@watchable/store"; // esm
const { createStore } = require("@watchable/store"); //commonjs
const store = createStore({ counter: 0 });
See below for compile-time Immutable state in Typescript!
In React...
import { useSelected } from "@watchable/store-react";
const counter = useSelected(store, (state) => state.counter);
// get and set keyed property, like React useState
const [counter, setCounter] = useStateProperty(store, "counter");
In pure business logic...
// watching the store
store.watch((state) => console.log(`Counter is ${state.counter}`));
// follow a selector (called back any time the selected value changes)
import { followSelector } from "@watchable/store-follow";
followSelector(
store,
(state) => state.counter,
(counter) => {
console.log(`Counter is ${counter}`);
}
);
Using a draft...
import { edit } from "@watchable/store-edit";
edit(store, (draft) => (draft.counter += 1));
Using an immutable pattern...
// read state
const state = store.read();
store.write({
...state,
counter: state.counter + 1,
});
Immutable
makes state recursively readonly to prevent inadvertent edits of
retrieved store state!
import { createStore, type Immutable } from "@watchable/store";
type CounterState = Immutable<{
counter: number;
}>;
const store = createStore<CounterState>({
counter: 0,
});
Declare functions to consume readonly data like this...
function processData(list: Immutable<number[]>) {}
If legacy code has compile errors, Draft<Immutable<T>>
recursively removes the
readonly modifier turning Immutable<T>
back into T
...
const { list } = store.read();
legacyOperation(list as Draft<typeof list>);
N.B. If you bypass the compiler with
Draft<T>
check thatlegacyOperation()
doesn't actually modify store data. This would bypassstore.write()
and watchers won't be notified of the modification, leading to bugs.
472 gzipped bytes of powerful state-management!
When a new state is passed to store.write(), user interfaces and business logic are notified of changes to state matching their Selectors.
@watchable/store is incredibly simple, lightweight and framework-independent, and therefore suited to manage state within almost any server-side or client-side Typescript or Javascript project.
Read the API Reference, examine the example code below, or browse the source on Github.
The Example Counter
Apps offer minimal
demonstrations of @watchable/store