Expressive State

Expressive State

A class-based state backbone for modern UI applications

Expressive State is a reactive state library built around plain classes. It's designed to be the backbone of your application - the place where data, behavior, and lifecycle live - so that components can go back to doing what components are best at: describing UI.

import State from '@expressive/react';

class Counter extends State {
  count = 0;

  increment() {
    this.count++;
  }

  decrement() {
    this.count--;
  }
}

function CounterWidget() {
  const { count, increment, decrement } = Counter.use();

  return (
    <div>
      <button onClick={decrement}>-</button>
      <span>{count}</span>
      <button onClick={increment}>+</button>
    </div>
  );
}

No reducers. No selectors. No dependency arrays. No extra libraries for async, context, or computed values. Just a class and a hook.


Why it exists

Most React apps outgrow their state. What starts as useState sprawls into useEffect chains, useCallback memoization, custom hooks that return objects of hooks, then a store library, then middleware for async, then a query client. By the time a feature is "done", its logic is scattered across five different primitives - none of which are easy to test, reuse, or understand in isolation.

Expressive takes a different approach: put the logic back in one place. A State class holds everything a feature knows and does. Components subscribe to what they need and render it. The two concerns - data and presentation - stop fighting each other.


What you get from a single import

  • Reactive properties - plain class fields that components subscribe to automatically.
  • Computed values - derived properties that update when their inputs change.
  • Async + Suspense - declarative data loading with built-in Suspense integration.
  • Context - type-safe dependency injection; the class is the context key.
  • Lifecycle - one new() hook for setup and teardown. No dependency arrays.
  • Components - the Component class lets state render itself, with built-in error boundaries and subcomponents.
  • Testability - state classes are plain objects. Test them without a renderer, without act(), without a DOM.

Where to go next

On this page