JSPM

use-tiny-state-machine

0.0.2
  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 210
  • Score
    100M100P100Q87830F
  • License MIT

A tiny (~700 bytes) react hook to help you write finite state machines

Package Exports

  • use-tiny-state-machine

This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (use-tiny-state-machine) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.

Readme

useTinyStateMachine

A tiny (~700 bytes) react hook to help you write finite state machines

CircleCI npm bundle size (minified + gzip) Codecov

Read the documentation for more information

Install

Import

yarn add use-tiny-state-machine

Examples

Manual traffic lights

import useTinyStateMachine from 'use-tiny-state-machine';

const stateChart = {
  id: 'traffixLight',
  initial: 'green',
  states: {
    green: { on: { NEXT: 'red' } },
    orange: { on: { NEXT: 'green' } },
    red: { on: { NEXT: 'orange' } },
  },
};

export default function ManualTrafficLights() {
  const { cata, state, dispatch } = useTinyStateMachine(stateChart);

  return (
    <Fragment>
      <div
        className="trafficLight"
        style={{
          backgroundColor: cata({
            green: '#51e980',
            red: '#e74c3c',
            orange: '#ffa500',
          }),
        }}
      >
        The light is {state}
      </div>
      <button onClick={() => dispatch('NEXT')}>Next light</button>
    </Fragment>
  );
};

Automated traffic lights with onEntry action

onEntry is called every time you enter a given state. onEntry is called with the current state machine instance.

import useTinyStateMachine from 'use-tiny-state-machine';

const stateChart = {
  id: "traffixLight",
  initial: "green",
  states: {
    green: {
      onEntry: waitForNextLight,
      on: {
        NEXT: "red"
      }
    },
    orange: {
      onEntry: waitForNextLight,
      on: {
        NEXT: "green"
      }
    },
    red: {
      onEntry: waitForNextLight,
      on: {
        NEXT: "orange"
      }
    }
  }
};

function waitForNextLight({ dispatch }) {
  const timer = setTimeout(() => dispatch('NEXT'), 1000);
  return () => clearTimeout(timer);
}

function TrafficLights() {
  const { cata, state, dispatch } = useTinyStateMachine(stateChart);

  return (
    <Fragment>
      <div
        style={{
          width: "30px",
          height: "30px",
          backgroundColor: cata({
            green: "#51e980",
            red: "#e74c3c",
            orange: "#ffa500"
          })
        }}
      >
        The light is {state}
      </div>
      <button onClick={() => dispatch("NEXT")}>Force next light</button>
    </Fragment>
  );
}

Fetching data

You can use context to store any data associated with a state.

const stateChart = {
  id: 'userData',
  initial: 'idle',
  context: {
    data: null,
    error: null,
  },
  states: {
    idle: {
      on: {
        FETCH: {
          target: 'pending',
          action: ({ dispatch }, userId) => {
            fetchUser(userId)
              .then(user => dispatch('SUCCESS', user))
              .catch(error => dispatch('FAILURE', error));
          },
        },
      },
    },
    pending: {
      on: {
        SUCCESS: {
          target: 'success',
          beforeStateChange: ({ updateContext }, data) => updateContext(c => ({ ...c, data })),
        },
        FAILURE: {
          target: 'failure',
          beforeStateChange: ({ updateContext }, error) => updateContext(c => ({ ...c, error })),
        },
      },
    },
  },
};

const UserData = () => {
  const { context, dispatch, cata } = useTinyStateMachine(stateChart);
  return (
    <div>
      {cata({
        idle: () => (
          <button onClick={() => dispatch('FETCH')}>
            Fetch user data
          </button>
        ),
        pending: () => <Spinner />,
        success: () => `Hi ${context.data.name}`,
        failure: () => `Error: ${context.error.message}`,
      })}
    </div>
  );
};