Section 04 / API Doc_id state Read_time 2 min

state

The state export is a function that returns a state object. A state can take transitions, immediates, reducers and actions as arguments.

import { createMachine, state, transition, immediate, reduce } from 'robot3';

const machine = createMachine({
  idle: state(
    transition('first', 'input')
  ),

  input: state(
    immediate('idle',
      reduce((ctx, ev) => ({ ...ctx, first: ev.target.value }))
    )
  )
});

Entering a state

Reducers and actions passed directly to state run every time the machine enters that state. Use them to set up the context a state needs, next to the state that needs it:

import { createMachine, state, transition, reduce, action } from 'robot3';

const machine = createMachine({
  welcome: state(
    reduce(ctx => ({ ...ctx, buttonLabel: 'Get started' })),
    transition('next', 'profile')
  ),
  profile: state(
    reduce(ctx => ({ ...ctx, buttonLabel: 'Save profile' })),
    action(() => analytics.track('profile_viewed')),
    transition('next', 'done')
  ),
  done: state()
});

Entry reducers and actions:

  • Run when the machine starts in the state, and every time it enters the state through a transition or immediate.
  • Run after the reducers on the transition that led into the state, and receive the same event.
  • Run before the state’s immediates are checked, so immediate guards see the updated context.
  • Run in the order they are listed, like reducers on a transition.
  • Do not run on a transition from a state to itself, such as transition('input', 'editing') inside the editing state. These self-transitions are commonly used to update context while staying in place, and re-running entry reducers would undo those updates.

Entry reducers and actions are supported by state only. They are not supported by invoke.

Final state

A state with no transitions or immediates. A state that only has entry reducers or actions is still final. In other libraries you have to make a state as final with { type: 'final' } or some other sort of configuration. We don’t have a configuration because it is not necessary; by definition a machine with no transitions cannot go to another state anyways.

You might find it convenient to have a final function anyways. You can achieve this by aliasing state to final like so:

import { createMachine, state, state as final } from 'robot3';

const machine = createMachine({
  pending: state(
    transition('done', 'finished')
  ),
  finished: final()
});

This improves readability so it is a recommended pattern.