cassiozen / useStateMachine

The <1 kb state machine hook for React
MIT License
2.38k stars 47 forks source link

Custom Events, Send returned from Update #37

Closed cassiozen closed 3 years ago

cassiozen commented 3 years ago

This PR 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');
  2. 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 });

Closes #28, #31 and #35

github-actions[bot] commented 3 years ago

size-limit report 📦

Path Size
dist/usestatemachine.cjs.production.min.js 391 B (+2.63% 🔺)
dist/usestatemachine.esm.js 423 B (+4.19% 🔺)
cassiozen commented 3 years ago

New Size Badge

useStateMachine size badge