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

ergo-react

v0.1.5

Published

React adapter for ergo-state — generated use<Name>() hooks for selector-driven render paths.

Downloads

495

Readme

Ergo React

The API you'd already write by hand — generated for you.

ergo-react is the React adapter for ergo-state. It uses the same store builder and store API conventions as Ergo, then adds generated use<Name>() hooks for selectors and autoselectors.

Use this package when a store is consumed from React render paths. Use ergo-state directly when a store only needs getters, subscribers, actions, middleware APIs, and full-state get / set.

Installation and peer dependencies

npm install ergo-react zustand react use-sync-external-store
# or
yarn add ergo-react zustand react use-sync-external-store
# or
pnpm add ergo-react zustand react use-sync-external-store

ergo-react depends on the base ergo-state package and has React-specific peer dependencies: react, use-sync-external-store, and zustand.

The React integration is built and tested for Single Page Applications using React 18+. Server-side rendering and hydration compatibility are not part of the supported scope. They may work in some setups, but they are not a compatibility target and should be validated by the consuming application.

Value add

Ergo believes your state management implementation details shouldn't find their way into your React components. Ergo React keeps the base Ergo API and adds generated hooks:

  • get<Name>() for imperative reads.
  • subscribe<Name>(listener) for non-React subscriptions.
  • use<Name>() for React render paths.
  • actions for domain mutations kept outside the state object.
  • middleware.<name> for lifecycle APIs added by Zustand middleware.

The main benefit is that selector definitions stay in the store module while React consumers import stable, domain-named hooks. Components do not need to import raw Zustand hooks, selector functions, or store internals.

This is the same wrapper hook teams often hand-write to avoid leaking state shape into components:

// what you'd hand-write around useStore / Redux's useSelector
function useModalIsOpen() {
  return useStore(modalStore, state => state.isOpen);
}
// what a selector definition already gives you in ergo-react
export const { useIsOpen: useModalIsOpen } = modalStoreApi;

useModalIsOpen() reveals nothing about what's underneath — it could be Zustand, Redux, Context, or something else entirely. useStore(state => state.modal.isOpen) and Redux's useSelector(state => state.modal.isOpen) can't make that promise: writing the selector means the caller already knows the state's shape.

Hand-writing that wrapper is fine for one value. It stops being fine once you have many stores and dozens or hundreds of selectors across a growing app: it's a near-identical function per value, repeated per store, with no compiler check that anyone actually wrote one for a new selector before a component reaches into the store directly instead. ergo-react generates the whole set from the same selector definitions that already back get<Name>() and subscribe<Name>(), so there's nothing to hand-write and nothing to fall out of sync. See Neutral interfaces vs. exposed internals for the full argument, including what it looks like when a component skips the wrapper hook entirely.

Quick start

import { createErgoStore } from 'ergo-react';

interface CounterState {
  count: number;
}

export const counterStoreApi = createErgoStore<CounterState>()
  .withInitialState(() => ({
    count: 0
  }))
  .withAutoselectors(['count'])
  .withoutActions();

export const { getCount, subscribeCount, useCount } = counterStoreApi; // The "useCount" export is what sets `ergo-react` apart from `ergo`

Main documentation

The core builder, selector, action, state-surface, equality, middleware, and factory behavior is documented in ergo-state. Start there for those concepts, then use the React-specific guide here for hook export patterns.

For libraries that export inferred store factories, ErgoReactStoreApi and ErgoReactStoreSelectorMap are public types. TypeScript declaration emit names these through ergo-react; consumers do not need to depend on ergo-state internals.

Guide