0.0.2 • Published 4 years ago

use-tiny-state-machine v0.0.2

Weekly downloads
114
License
MIT
Repository
github
Last release
4 years ago

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>
  );
};