npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@smoothbricks/statebus-react

v0.1.7

Published

React bindings and browser scheduler for StateBus.

Readme

StateBus React

One createBusApi factory builds the API for either a reusable library or an application. It returns ready-to-use hooks, a provider, and a function that creates independent StateBus instances. A hosted library's hooks use the application's bus, not a second library store.

Build the library API

import { createBusApi } from '@smoothbricks/statebus-react';

export const counter = createBusApi({
  name: 'counter',
  setup(builder) {
    const count = builder.scalar('count', () => 0);
    const increment = builder.event<number>('increment');
    builder.reduce(increment, (state, amount) => {
      state.set(count, state.read(count) + amount);
    });
    return { count, increment };
  },
});

export const { useBus, useStateValue, useEventPublisher } = counter;

export function Counter() {
  const count = useStateValue(model => model.count);
  const increment = useEventPublisher(model => model.increment);
  return <button type="button" onClick={() => increment(1)}>{count}</button>;
}

The setup function declares state and reducers but does not create live state or perform I/O. The returned functions are bound to this library's identity, not to a particular standalone bus. Destructuring them does not lose a this binding. Their types are inferred from setup's exports.

Use it standalone or inside an application

A standalone entry point creates its own bus and supplies it to the provider:

const { createBus, Provider } = counter;
const bus = createBus();
root.render(<Provider bus={bus}><Counter /></Provider>);
// At the real application boundary: root.unmount(); await bus.disposeAsync();

A host uses the same factory and the unchanged library component:

const app = createBusApi({
  name: 'application',
  libraries: { counter },
  setup(builder, libraries) {
    const publicCounter = libraries.get('counter');
    const updates = builder.scalar('updates', () => 0);
    builder.reduce(publicCounter.increment, state => {
      state.set(updates, state.read(updates) + 1);
    });
    return { updates };
  },
});

const { createBus, Provider, useBus } = app;
const bus = createBus();
root.render(<Provider bus={bus}><Counter /></Provider>);

These snippets are separate entry points. root is the application's React root. No extra counter provider is needed for a unique inclusion. counter.useBus().instance and app.useBus().instance refer to that exact same live bus, while their exports contain the appropriate typed handles. A public library never imports its host's state or proprietary types.

useBus() returns stable BusAccess: typed exports, the actual instance, reader/publication functions and library(name) for included APIs. It does not subscribe to a whole-state snapshot. Rendering values requires a state/selection hook. Repeated calls return the same access object until the provider selects another bus or library occurrence.

Fine-grained reads, events and selections

| Returned hook | Signature and behavior | | --- | --- | | useBus() | Stable access to this API in the provider's bus; no state subscription | | useStateValue(model => model.scalar) | Subscribe to one scalar/resource handle | | useKeyedState(model => model.keyed, id) | Subscribe to one keyed atom; preserves the handle's branded ID type | | useEventPublisher(model => model.event) | Stable typed event publisher; no state subscription | | createSelectionHook(name, select, interests?) | Build a hook whose computed value depends on selected atoms and primitive props |

The scalar/keyed/event selector chooses a declaration from the library's resolved exports, not a snapshot. The binding keys on the resulting handle, bus and resource ID, not the selector lambda's identity. Inline selectors therefore do not resubscribe merely because a component renders again.

For a resource library exporting stock and incoming, a computed hook has this shape:

const useSummary = inventory.createSelectionHook(
  'inventory.summary',
  (state, model, props: { id: ShelfId }) => ({
    stock: state.readKeyed(model.stock, props.id),
    incoming: state.readKeyed(model.incoming, props.id),
  }),
  (model, props) => [model.stock.at(props.id), model.incoming.at(props.id)],
);

inventory and ShelfId above are the application's declared API and branded ID type. The complete synthetic example is statebus-core/scripts/consumer/composed/bus-api.ts and its local library/codecs.

Hooks reuse the existing per-atom external-store subscriptions and committed computed binding. Unrelated host state does not rebuild library snapshots. Switching IDs releases old interest and acquires new interest. StrictMode cleanup releases leases; it does not dispose the shared bus.

Include a library twice

Repeated inclusion is intentionally explicit at the subtree that needs a particular occurrence:

const app = createBusApi({
  name: 'comparison',
  libraries: { left: counter, right: counter },
  setup: () => ({}),
});
const bus = app.createBus();
const selected = app.getBus(bus).library('left');

root.render(
  <app.Provider bus={bus}>
    <counter.Provider scope={selected}>
      <Counter />
    </counter.Provider>
  </app.Provider>,
);

The scope only selects that occurrence's handles inside the existing bus. It allocates no second state store and starts no operations. Unqualified counter.useBus() under this app refuses the ambiguity instead of choosing a random/first occurrence. A scope from another bus is rejected. Scopes and publishers are stable; changing the scope replaces subscriptions correctly. Nested APIs resolve the nearest selected occurrence and can still resolve unambiguous ancestor APIs.

Execution boundary, testing and replay

api.getBus(bus) provides the same typed access outside React. Use its exports when binding the existing bindEffect, composedLoaderChannel and bindComposedQueryLoader APIs. The application owns QueryClient, production clients, navigation, request IDs, tracing contexts and disposal. There is no new operation framework or implicit global bus.

Providers call the existing required-effect preflight before rendering children. They never create, dispose or replace an instance on their own. The core factory can also create included libraries without depending on React; its recipe identity works with the React factory's host provider.

const bus = app.createBus({ scheduler: new ManualScheduler() });
const recorder = recordScenario(bus);
// Drive the same reducers, planners and decoders through real events/controlled operations.
const replay = app.replayScenario(recorder.snapshot());
// replay is another StateBus with effect/query execution disabled.

ManualScheduler and recordScenario are core exports, also re-exported by the React package. Supply codecs before recording. Each test/story creates and disposes its own bus. Envelope capture, owned migrations and replay remain available through createCaptureEnvelope, migrateCaptureEnvelope and replayCaptureEnvelope on the returned API; see the core guide and replay contract.

The existing package-level ambient hooks and lower-level composition bindings remain exported; import the new hooks from your returned API, rather than mixing its provider with ambient useBus. The factory's instance is the existing composed engine, not the separate animation-frame alias.

Verification

nx run statebus-core:verify-packages checks strict declarations and executes this factory's standalone/hosted/repeated-library, real ReactDOM StrictMode, exact loader interest, duplicate-command, late-resource-result and no-I/O replay scenarios through actual built package exports under Node/Bun and isolated/hoisted installs. The existing browser and package suites remain enabled.

Names and library routing are resolved during API construction. Per-bus access objects are prepared before rendering. No schema reconstruction, resource stringification or global snapshot is added to ordinary reads/publications. This is an implementation contract, not a claim of measured allocation, GC or latency improvement for the factory itself.