Finite State MachineLoading saved progress…

Finite State Machine

"Loading spinner still showing after an error", "submit fires twice", "back button lands in an impossible screen" — most UI bugs are really state bugs: the app drifted into a combination you never intended. A finite state machine kills that whole class by making the legal states and the transitions between them explicit data. You're in exactly one state; an event either has a defined transition out of it or it's ignored. Libraries like XState are built on this; here you'll write the tiny interpreter at its heart.

Implement finiteStateMachine(config) returning a machine with send, can, matches, and subscribe, supporting guards and entry actions. See statecharts.dev.

Signature

function finiteStateMachine(config) {
  return { state, context, send, can, matches, subscribe };
}

Examples

const m = finiteStateMachine({
  initial: 'idle',
  context: { data: null },
  states: {
    idle: { on: { FETCH: 'loading' } },
    loading: {
      on: {
        SUCCESS: { target: 'ok', action: (ctx, e) => { ctx.data = e.data; } },
        ERROR:   { target: 'fail', guard: (ctx, e) => e.fatal === true },
      },
    },
    ok: {}, fail: {},
  },
});

m.send('FETCH');                     // -> 'loading'
m.send({ type: 'SUCCESS', data: 7 }); // -> 'ok', ctx.data === 7

Notes

  • A transition is a lookup — for the current state, find on[event.type]. No entry → ignore the event (stay put). Events are strings or { type, ...payload }.
  • Guards gate transitions — if a transition has a guard, it fires only when guard(context, event) is truthy; otherwise the machine stays.
  • Actions and entry — a transition's action runs during the switch; the target state's entry runs on arrival. The initial state's entry runs once at creation.
  • can, matches, subscribecan(event) previews whether a transition would fire; matches(state) checks the current state; subscribe notifies on each real transition.
WE’RE LISTENING

Help make UIReady better

Found a bug or have an idea? Tell us about it.

Up to 3 files · 5 MiB each · JPG, PNG, WebP, MP4, WebM, MP3, M4A or WAV