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 🙏

© 2025 – Pkg Stats / Ryan Hefner

fsm-hook

v0.1.4

Published

If your components have multiple states and you want to have a clear and maintainable way to manage them, you can use this library.

Readme

Why ?

If your components have multiple states and you want to have a clear and maintainable way to manage them, you can use this library.

It is a simple finite state machine as a hook.

React docs ref - https://react.dev/learn/managing-state
Wiki - https://en.wikipedia.org/wiki/Finite-state_machine

Features

  • finite state machine as hook
  • initial state
  • transitions
  • history
  • logs
  • typesafe FSM map
  • typesafe transition
  • 100% code coverage
  • size: 698 B (with all dependencies, minified and brotlied)

What is not

  • Event Emitter: This library does not handle event emission.

  • Logic Provider: It does not provide business logic.

  • Side Effect Handler: It does not manage side effects.

  • Component Render: It does not handle component rendering.

Comparison

With Statex/store:

According to Statex/store documentation, "It is comparable to libraries like Zustand, Redux, and Pinia."

So, there's no need for further comparison. It's not a pure finite state machine; it's a more complex solution. useFSM is a pure finite state machine without additional functionality.

With cassiozen/useStateMachine:

It's a nice and small solution, but it includes side effect handling. The code that describes the state machine is about 10 times larger compared to useFSM. Additionally, cassiozen/useStateMachine doesn't have history.

Install

npm install fsm-hook

Examples

Full example:

import { FSMProvider, useFSM } from "fsm-hook";

const customLogger = {
  log: (message: string) => console.log(message),
  warn: (message: string) => console.warn(message),
};

const App = () => {
  const {
    currentState,
    transition,
    undo,
    availableTransitions,
    getHistory,
  } = useFSM(
    "idle", // Initial state
    {
      // Define state transitions
      idle: { typing: "fillForm" },
      fillForm: { submitting: "waitSubmitting", canceling: "idle" },
      waitSubmitting: { success: "done", failure: "fail", reset: "idle" },
      fail: { restart: "idle" },
      done: {},
    },
    { logLevel: "debug", maxHistoryLength: 10 } // !This configuration override FSMProvider config
  );

  return (
    <div>
      <p>Current State: {currentState}</p>
      <p>Available Transitions: {availableTransitions().join(", ")}</p>
      <button onClick={() => transition<"idle">("typing")}>Start Typing</button>
      <button onClick={() => transition("submitting")}>Submit</button>
      <button onClick={() => transition("canceling")}>Cancel</button>
      <button onClick={() => transition("success")}>Success</button>
      <button onClick={() => transition("failure")}>Failure</button>
      <button onClick={() => transition("restart")}>Restart</button>
      <button onClick={() => transition("reset")}>Reset</button>
      <button onClick={undo}>Undo</button>

      <p>History: {getHistory().join(" -> ")}</p>
    </div>
  );
};

const Root = () => (
  <FSMProvider config={{ logLevel: "debug", maxHistoryLength: 10, logger: customLogger }}>
    <App />
  </FSMProvider>
);

export default Root;

Structure of transitions map

{
  'STATE1_NAME': { 'TRANSITION1_NAME': 'STATE2_NAME'  }
  'STATE2_NAME': { 'TRANSITION2_NAME': 'STATE1_NAME','TRANSITION3_NAME': 'STATE3_NAME'   }
  'STATE3_NAME': { 'TRANSITION4_NAME': 'STATE4_NAME'  },
  'STATE4_NAME': {}
}

Key Features in Action

  • Initial State: The FSM starts in the idle state.

  • Transitions: Buttons trigger state transitions (e.g., typing moves from idle to fillForm).

  • History: The history of state changes is tracked and displayed.

  • Undo: The undo function allows reverting to the previous state.

  • Logging: Custom logging is enabled for debugging.

Configuration Options

The FSMProvider and useFSM hook accept the following configuration options:

  • logLevel: Set the logging level (debug, info, warn, error).

  • maxHistoryLength: Limit the number of states stored in history.

  • logger: Provide a custom logger object with log and warn methods.

Type Safety

The library ensures type safety when defining your FSM:

  • Invalid States: Errors are thrown if a state is not defined or unused.

  • Invalid Transitions: Errors are thrown if a transition leads to an invalid state.

Example of type-safe transitions:

useFSM("idle", {
  idle: { typing: "fillForm" }, // Error if 'fillForm' is not a valid state
  done: {}, // Error if 'done' is not used in any transition
});

Debugging with Mermaid Diagrams

You can generate a Mermaid diagram to visualize your state machine:

import { generateMermaidDiagram } from "fsm-hook";

const diagram = generateMermaidDiagram({
  idle: { typing: "fillForm" },
  fillForm: { submitting: "waitSubmitting", canceling: "idle" },
  waitSubmitting: { success: "done", failure: "fail", reset: "idle" },
  fail: { restart: "idle" },
  done: {},
});

console.log(diagram);

And put result here - https://www.mermaidchart.com/play