useStateMachine

The <1 kb state machine hook for React

MIT License

Stars
2.4K
useStateMachine - 1.0.0 Latest Release

Published by cassiozen almost 3 years ago

No changes, just re-released as 1.0.0 and out of Beta.

useStateMachine - 1.0.0-beta.4

Published by cassiozen about 3 years ago

Api changes for sendT (#72)

useStateMachine - 1.0.0-beta.3

Published by cassiozen about 3 years ago

feat(dx): instantiate all boundary types (#76 )

useStateMachine - The one with txstate

Published by cassiozen about 3 years ago

This release contains a implementation, porting and expanding on txstate library. It provides:

  • better error messages:

    Before -
    image
    image

    After -
    image
    image

    Before -
    image
    image

    After -
    image
    image

  • Typed guards hence inferring context typestates

    // example picked from xstate docs
    let [flightMachine] = useStateMachine<FlightMachineContext>({ trip: 'oneWay' })({
      initial: 'editing',
      states: {
        editing: {
          on: {
            SUBMIT: {
              target: 'submitted',
              guard: (context): context is FlightMachineSubmittedContext => {
                if (context.trip === 'oneWay') {
                  return !!context.startDate;
                } else {
                  return (
                    !!context.startDate &&
                    !!context.returnDate &&
                    context.returnDate > context.startDate
                  );
                }
              }
            }
          }
        },
        submitted: {}
      }
    })
    
    type FlightMachineEditingContext =
      { trip: 'oneWay' | 'roundTrip'
      , startDate?: Date
      , returnDate?: Date
      }
    type FlightMachineSubmittedContext =
      | { trip: 'oneWay'
        , startDate: Date
        }
      | { trip: 'roundTrip'
        , startDate: Date
        , returnDate: Date
        }
    
    type FlightMachineContext =
      | FlightMachineEditingContext
      | FlightMachineSubmittedContext
    
    expectType<FlightMachineContext>(flightMachine.context);
    if (flightMachine.value === 'submitted') {
      expectType<FlightMachineSubmittedContext>(flightMachine.context);
      
      if (flightMachine.context.trip === 'oneWay') {
        expectError(flightMachine.context.returnDate)
      }
    }
    
  • New API, without the curried function workaround and with better support for typed events.

Credits: This was possible by the amazing effort of @devanshj

useStateMachine - 1.0.0-beta.1

Published by cassiozen over 3 years ago

  • Grouped verbose log (#43)
  • Top-level transitions (#49)
  • New param signature for effects & guards (#48)
  • Added inline docs (#47)
useStateMachine - 0.4.1

Published by cassiozen over 3 years ago

  • Fixed a bug where events sent in object format were not properly logged in verbose mode (@arthurdenner)
  • Allow self-transitions (transitioning to the same state, will re-run effects)
useStateMachine - 0.4.0

Published by cassiozen over 3 years ago

This versions solves two issues:

  1. Returns send from update:
    A Common pattern is to update the context then immediately send an event to transition as illustrated by the async example). With this PR, the following two lines:
update(context => ({ data: coffees, ...context }));
send('SUCCESS');

Can now be written as:

update(context => ({ data: coffees, ...context })).send('SUCCESS');
  1. Allows events to contain arbitrary payload:
    Until now there was no simple way to bring outside data into the state machine context (like a form or a subscription). With this PR, events can be sent in an object notation in addition to the string notation: (e.g. send("TOGGLE") or send({ type: "TOGGLE" }). The latter accepts arbitrary keys and values that can be accessed inside effects and guards.
const [machine, send] = useStateMachine<{ time: number }>({ time: 0 })({
  initial: 'idle',
  verbose: true,
  states: {
    idle: {
      on: {
        START: 'running',
      },
      effect(_, update, event) {
        update(() => ({ time: event?.resetTime }));
      },
    },
    running: {
      on: {
        STOP: 'idle',
      },
      effect(_, update) {
        // ...
      },
    }
  },
});

send({ type: 'STOP', resetTime: 10 });

By default all additional values are typed as any, but the user can provide custom types as a generic:

const [machine, send] = useStateMachine<{ time: number }, { type: 'START' } | { type: 'STOP'; resetTime: number }>({
  time: 0,
})({
  initial: 'idle',
  verbose: true,
  states: {
    idle: {
      on: {
        START: 'running',
      },
      effect(_, update, event) {
        if (event?.type === 'STOP') update(() => ({ time: event?.resetTime }));
      },
    },
    running: {
      on: {
        STOP: 'idle',
      },
      effect(_, update) {
        // ...
      },
    },
  },
});

send({ type: 'STOP', resetTime: 10 });
useStateMachine - 0.3.2

Published by cassiozen over 3 years ago

Provides a stable send method.

useStateMachine - 0.3.1

Published by cassiozen over 3 years ago

Fixes ESM configuration

useStateMachine - 0.3.0

Published by cassiozen over 3 years ago

  • Added verbose mode (#13 )
  • Huge typing refactor (#11)
useStateMachine - 0.2.1

Published by cassiozen over 3 years ago

Fixes a bug where configurations containing states with no events would cause send to be typed as never (#9)

useStateMachine - 0.2.0

Published by cassiozen over 3 years ago

New API for guards and effects.

useStateMachine - 0.1.1

Published by cassiozen over 3 years ago