UseStateMachine Versions Save

The <1 kb state machine hook for React

1.0.0

2 years ago

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

1.0.0-beta.4

2 years ago

Api changes for sendT (#72)

1.0.0-beta.3

2 years ago

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

1.0.0-beta.2

2 years ago

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

  • better error messages:

    Scenario 1


    Before - image image

    After - image image

    Scenario 2


    Before - image image

    After - image image

  • Typed guards hence inferring context typestates

    Example
    // 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

1.0.0-beta.1

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

0.4.1

2 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)

0.4.0

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

0.3.2

2 years ago

Provides a stable send method.

0.3.1

2 years ago

Fixes ESM configuration

0.3.0

2 years ago
  • Added verbose mode (#13 )
  • Huge typing refactor (#11)