Module @watchable/store

Minimal watchable state for your app

Install

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

Summary

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 OR Require

import { createStore } from "@watchable/store"; // esm
const { createStore } = require("@watchable/store"); //commonjs

Create a Store (Javascript)

const store = createStore({ counter: 0 });

See below for compile-time Immutable state in Typescript!

Track State

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}`);
}
);

Read and Write State

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,
});

A type-safe Store (Typescript)

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 that legacyOperation() doesn't actually modify store data. This would bypass store.write() and watchers won't be notified of the modification, leading to bugs.

Description

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.

Demonstration Apps

The Example Counter Apps offer minimal demonstrations of @watchable/store

Index

Interfaces

Type Aliases

Functions