Skip to content

Hooks

Lifecycle

Every event sent to the machine goes through the following phases:

  • resolve
  • transition
    • guard
    • handle
    • before
    • update
    • effect
      • leave
      • enter
    • notify
    • after

Is this overkill? Probably. The main ones to use are guard and effect.

leave and enter are useful to ensure that such transition effects do not interfere with one another. All leave handlers run before any enter handlers.

46 lines, 1043 chars
const states = defineStates({
  Idle: undefined,
  Pending: (x: number) => ({ s: `#${x}` }),
  Resolved: (ok: boolean) => ({ ok }),
  Rejected: (err: Error) => ({ err }),
});

const m4 = createFactoryMachine(
  states,
  {
    Idle: { execute: "Pending" },
    Pending: { resolve: "Resolved", reject: "Rejected" },
    Resolved: {},
    Rejected: {},
  },
  "Idle",
);
m4.getChange().to.key = "Pending";

setup(m4)(
  guard((ev) => ev.type !== "execute" || ev.params[0] > 0),
  leave((ev) => {
    if (ev.type === "execute") {
      console.log("executing");
    }
  }),
  enter((ev) =>
    console.log(
      ev.to.match<any>({
        Pending: (ev) => ev.s,
        Resolved: (ev) => ev.ok,
        Rejected: (ev) => ev.err,
        _: () => false,
      }),
    ),
  ),
);

m4.send("execute", 1);

Lifecycle

Action: or
{
  "Current State Key": "Idle",
  "Last Change": {
    "type": "__initialize",
    "to": {
      "key": "Idle"
    }
  }
}
Log:

Code:

onLifecycle(machine, {
  Idle: {
    on: {
      execute: {
        after: ({ type, from, to }) => {
          console.log(
            "Specific state and event:\n",
            type, // MUST equal and autocomplete to 'execute'
            "from", from.key, // MUST equal and autocomplete to 'Idle'
            "to", to.key, // MUST equal and autocomplete to 'Pending'
          )
        },
      },
    },
  },
  "*": {
    on: {
      "*": {
        after: ({ type, from, to }) => {
          console.log(
            "any state with any event:\n",
            type, // any valid event b/c wildcard event
            "from", from.key, // any valid state b/c wildcard state
            "to", to.key, // any valid exit state (which excludes Idle)
            "with data", to.data, // any valid state data b/c wildcard state
          )
        },
      },
      reject: {
        after: ({ type, from, to }) => {
          const { name, stack, message } = to.data // can only be Error type
          console.log(
            "Any reject event:\n",
            type, // MUST be 'reject'
            "from", from.key, // any valid state b/c wildcard state
            "with data", from.data, // any valid state data b/c wildcard state
            "to", to.key, // MUST equal and autocomplete to 'Rejected'
            "Error", name, message, stack, // Error properties
          )
        },
      },
    },
  },
})