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

@heliopolis/hooks

v0.4.1

Published

A utility library with a few convenient hooks for React / Mobx

Readme

Modular hooks

This little utility library provides a few helpful hooks and hook factories for working with function components in React >=16.9.

Actors

State can be managed in a safe way with 2 helpful functions:

  • useActor(caseReducers, initialState)
  • createActorHook(stateFactory, caseReducers)

Given both functions require some state to be defined and some case reducers to act upon said state, let's define a function that initializes state and case reducers to act on this state.

interface Person {
  name: string
  age: number
}

function createPerson(name?: Person['name']): Person {
  return {
    name: name ?? 'Unnamed person',
    age: 40
  }
}

const reducers = {
  incrementAge(person: Person): Person {
    return {
      ...person,
      age: person.age + 1
    }
  },
  rename(person: Person, newName: Person['name']): Person {
    return {
      ...person,
      name: newName
    }
  }
}

Note: the inspiration for the Actor name is due to the similarities between the redux/reducer approach to state management and the Actor model. Namely, state is mutated internally by the actor (in this case, reducer) and changes to said state are effectuated by sending messages to the actor (actions to the reducer). Changes are handled linearly in the order in which they are received.

useActor

Designed for a reducer/redux-like experience, useActor is a convenience hook around useReducer that, given case reducers and an initial state, returns a state (like useReducer) and a set of type-safe dispatchers for each of the case reducers.

// Using `Person`, `createPerson` and `reducers` from the previous example

const initialPerson = createPerson('Sarah Kerrigan')

function PersonCard() {
  const [person, dispatchers] = useActor(reducers, initialPerson)

  return <div>
    <h1>Name: {person.name}</h1>
    {/* Text input whose `onEnter` callback is called when pressing ENTER */}
    <TextInput onEnter={dispatchers.rename} />
  </div>
}

// De-structuring is also supported since the hook returns plain JS objects

function PersonCard() {
  const [{ name }, { incrementAge, rename }] = useActor(reducers, initialPerson)

  // incrementAge: () => void
  // rename: (newName: string) => void

  return <div>
    <h1>Name: {name}</h1>
    <TextInput onEnter={rename}>
    <button onClick={incrementAge}>Age by 1 year</button>
  </div>
}

createActorHook

While useActor may be convenient, we can make this interface even more convenient by removing the boilerplate of providing the case reducers with every call to useActors. This is where createActorHook comes in.

Given case reducers and a factory that returns state, createActorHook will return a hook with the same signature as the provided factory. This hook when used will return a tuple of [state, dispatchers], precisely like useActor above while keeping component logic very readable.

// Using the `Person`, `createPerson` and `reducers` in the first example

const usePerson = createActorHook(createPerson, reducers)
// usePerson: (name?: string) => [Person, Dispatchers]

function PersonCard() {
  const [{ name }, { rename }] = usePerson('Zeratul')

  return <div>
    <h1>Name: {name}</h1>
    <TextInput onChange={rename} />
  </div>
}

The main benefits we see here are:

  • No need to provide reducers explicitly with every hook use
  • No mention of actors in the component which may allows us to stick to the language of our business domain
  • Customizable hook arguments signature since it inherits its arguments signature from the provided factory