Skip to content

Миграция с XState v5

vue-state-machine совместим по API с полезным подмножеством XState v5. Миграция простой машины обычно занимает считаные минуты.

Соответствие API

XState v5vue-state-machineЗаметки
createMachine(config)defineMachine(config)Структура конфига идентична
useMachine(machine) из @xstate/vueuseMachine(config)Та же форма composable
send(event)send(event)Идентично
matches(state)matches(state)Идентично
context в конфигеcontext в конфигеИдентично
Обработчики onОбработчики onИдентично
entry / exitentry / exitИдентично
type: 'final'type: 'final'Идентично
Функция guardФункция guardТа же сигнатура
assign(updater)Возврат Partial<context> из actionОбёртка не нужна
snapshot / restoresnapshot / restoreТа же концепция
invoke / сервисыНе поддерживаетсяПеренесите асинхронную работу в actions
spawn / модель акторовНе поддерживаетсяОсознанное ограничение области
Иерархические состоянияНе поддерживаетсяТолько плоские + параллельные

Пошаговая миграция

1. Замените импорт и фабрику:

ts
// До (XState v5)
import { createMachine } from 'xstate'
const machine = createMachine({ ... })

// После
import { defineMachine } from 'vue-state-machine'
const machine = defineMachine({ ... })

2. Замените assign() на обычные возвращаемые значения:

ts
// До
import { assign } from 'xstate'
const increment = assign({ count: (ctx) => ctx.count + 1 })

// После — просто верните частичный объект контекста
const increment = (ctx: { count: number }) => ({ count: ctx.count + 1 })

3. Замените импорт Vue-composable:

ts
// До
import { useMachine } from '@xstate/vue'

// После
import { useMachine } from 'vue-state-machine'

4. Перенесите асинхронную логику из invoke в actions:

ts
// До (XState v5 invoke)
loading: {
  invoke: {
    src: (ctx, event) => fetch('/api/user'),
    onDone:  { target: 'success', actions: assign({ user: (_, e) => e.data }) },
    onError: { target: 'error' },
  }
}

// После — fire-and-forget внутри компонента или внутри entry action
loading: {
  entry: [async (ctx, event) => {
    try {
      const user = await fetch('/api/user').then(r => r.json())
      return { user }       // сливается в контекст; затем SUCCESS отправляется извне
    } catch {
      return { error: 'Failed' }
    }
  }]
}