createXStateService function

The createXStateService function creates an XState service (a running instance of a state machine) that can be used within components.

A service is created using the createMachine function first followed by the createXStateService function. It is an instance created using the @xstate/fsm package.

The createXStateService function takes four arguments:

  1. service key (for example an.example.service) - keys must be unique and are used to retrieve services later (required)
  2. machine created with the createMachine function (required)
  3. an object of getter functions (optional)
  4. a persistence string, object or custom class (optional)
import { createMachine, createXStateService } from 'https://cdn.skypack.dev/ficusjs@6/xstate-service'

const definition = {
  /* define the machine definition */
}

const options = {
  /* define options like actions, guards etc */
}

// create the state machine
const machine = createMachine(definition, options)

// interpret the state machine to create a service
const service = createXStateService('toggle.service', machine)

A service can then be passed to as many components as required using the withXStateService function.

Getters

Getters are useful if you want to return a projection of the extended state (the state machine context is the extended state). A projection is a shape derived from the state.

Getters are memoized functions which means the result of the getter is cached for subsequent executions. This is useful when creating projections from large sets of data. State changes will automatically reset the getter cache.

To provide getters for creating projections, create an object containing functions and pass it to the createXStateService function as the third argument.

const getters = {
  isGlassFull (context) {
    return context.amount >= 10
  },
  remaining (context) {
    return 10 - context.amount
  }
}

// interpret the state machine to create a service
const service = createXStateService('toggle.service', machine, getters)

Persistence

To survive hard refreshes from the user, your state can be persisted to sessionStorage automatically.
This will re-hydrate your state machine on initialisation.

Passing a string as the persistence argument provides a namespace for persisting the state.

const service = createXStateService('toggle.service', machine, getters, 'food')

createPersist function

You can optionally save state to window.localStorage (for persistence across browser sessions) using the createPersist function:

import { createPersist } from 'https://cdn.skypack.dev/ficusjs@6'

const service = createXStateService('toggle.service', machine, getters, createPersist('food', 'local'))

When using the createPersist function, the following arguments must be supplied:

ArgumentTypeRequiredDescription
namespacestringtrueThe unique namespace for the store
storagestringtrueThe storage mechanism to use - either local for window.localStorage or session for window.sessionStorage (default)
optionsobjectPersistence options. See options below.

Options

Options can be provided when creating persistence.

import { createPersist } from 'https://cdn.skypack.dev/ficusjs@6'

const service = createXStateService('toggle.service', machine, getters, createPersist('food', 'local', {
  clearOnReload: true,
  saveState (state) {
    return {
      // only save the state value
      value: state.value
    }
  }
}))
options.clearOnReload

Setting options.clearOnReload to true will detect the browser reload state using
the window.performance API and clear the persistence
if a reload type is detected.

createPersist('food', 'local', {
  clearOnReload: true
})
options.saveState

Setting options.saveState provides a way to persist specific data different to that of the store state.
This is useful when the store state contains functions or other data that cannot be serialised into a string when saved
to window.sessionStorage or window.localStorage.

createPersist('food', 'local', {
  saveState (state) {
    return {
      // return properties of state to persist
    }
  }
})

The saveState function is passed the current state and must return an object of data to be serialised into a string.

Custom persistence

You can provide a custom class and persist your application state in whichever way you choose.

Four methods must be implemented:

MethodDescription
setState(state)Save the state in the persistence store
getState()Retrieve the state from the persistence store
lastUpdated()Retrieve the last updated time of the state in milliseconds since the Unix Epoch
removeState()Remove the state from the persistence store
class MyCustomPersist {
  setState (state) {
    // set the state
  }

  getState () {
    // get the state
  }

  lastUpdated () {
    // get the last updated time in milliseconds since the Unix Epoch
  }

  removeState () {
    // remove the state - this is called by default when setState is null
  }
}

const service = createXStateService('toggle.service', machine, getters, new MyCustomPersist())