Skip to content

State

The mesh holds your application state as a plain JavaScript object. You read it, write it, and subscribe to changes.

Read State

ts
// Get the full state object
const state = mesh.getState();

// Read a specific path
import { getPath } from "statemesh-core";
const theme = getPath(state, "theme");
const itemCount = getPath(state, "cart.items.length");

Write State

ts
// Replace the full state
mesh.setState({ theme: "dark", cart: { items: [], count: 0 } });

// Update a single path
mesh.setPath("theme", "dark");
mesh.setPath("cart.count", 5);
mesh.setPath("user.address.city", "New York");

setPath accepts dot-separated paths and creates intermediate objects as needed. The path "user.address.city" will create user.address if it doesn't exist.

Reset State

ts
// Reset to the initial state provided to createMesh
mesh.reset();

If undo/redo is enabled, reset() pushes the pre-reset state to the undo stack so the user can undo the reset.

Destroy

ts
// Clean up all subscriptions, plugins, timers, and resources
mesh.destroy();

WARNING

After calling destroy(), the mesh instance is unusable. Any further calls to getState(), setState(), subscribe(), etc. will throw.

Subscribe

Subscriptions let you react to state changes. You provide a selector (to extract a piece of state) and a callback (that runs when the selected value changes).

Basic Subscription

ts
const unsubscribe = mesh.subscribe(
  (state) => state.theme,
  (theme) => console.log("Theme changed to:", theme)
);

// Later: stop listening
unsubscribe();

Path-Based Subscription (React)

In React, use useMeshState or useMeshSelector for path-based subscriptions:

tsx
import { useMeshState, useMeshSelector } from "statemesh-core";

function ThemeDisplay() {
  const [theme, setTheme] = useMeshState<"light" | "dark">("theme");
  return <span>{theme}</span>;
}

function CartBadge() {
  const count = useMeshSelector((state) => state.cart.items.length);
  return <span>{count} items</span>;
}

Equality Functions

By default, subscriptions compare values by reference. You can provide a custom equality function:

ts
import { shallowEqual } from "statemesh-core";

mesh.subscribe(
  (state) => ({ theme: state.theme, lang: state.lang }),
  (value) => console.log("Theme or lang changed:", value),
  shallowEqual
);

The shallowEqual function compares each property of the selected object by reference. StateMesh also exports cloneState for deep cloning.

React Hooks for State

HookPurposeReturns
useMeshState(path)Read and write a state path[value, setValue]
useMeshSelector(selector)Read derived statevalue
useMesh()Access the mesh instancemesh
tsx
import { useMeshState, useMeshSelector, useMesh } from "statemesh-core";

function Example() {
  const [theme, setTheme] = useMeshState<"light" | "dark">("theme");
  const itemCount = useMeshSelector((s) => s.cart.items.length);
  const mesh = useMesh();

  return (
    <div>
      <p>Theme: {theme}</p>
      <p>Items: {itemCount}</p>
      <button onClick={() => mesh.reset()}>Reset</button>
    </div>
  );
}

Important Notes

TIP

setState and setPath trigger synchronous notifications to all subscribers. If you need to make multiple updates and only notify once, use mesh.batch().

WARNING

getState() returns a reference to the current state object. Do not mutate it directly — always use setState(), setPath(), or actions/transactions. Direct mutation bypasses subscriptions and can corrupt undo/redo history.

Next Steps

Released under the MIT License.