Skip to content

Определение машин ​

defineMachine(config) — чистая фабричная функция. Валидирует конфиг и возвращает его с улучшенными типами TypeScript. Ноль зависимости от Vue — можно вызывать и тестировать в Node без приложения Vue.

ts
function defineMachine<TState, TEvent, TContext>(
  config: MachineConfig<TState, TEvent, TContext>,
): MachineConfig<TState, TEvent, TContext>

Структура конфига ​

ts
const machine = defineMachine({
  id: 'login', // уникальный идентификатор (обязателен, используется DevTools и MachineStore)
  initial: 'idle', // начальное состояние
  context: {
    // опциональный начальный контекст (глубоко клонируется для каждого инстанса)
    attempts: 0,
    error: null as string | null,
  },
  states: {
    idle: {
      on: {
        // имя события → конфиг перехода
        SUBMIT: { target: 'loading', actions: [resetError] },
      },
    },
    loading: {
      on: {
        SUCCESS: { target: 'success' },
        FAILURE: { target: 'error', actions: [incrementAttempts] },
      },
    },
    error: {
      on: {
        RETRY: { target: 'idle', guard: canRetry },
      },
    },
    success: { type: 'final' }, // терминальное — дальнейшие вызовы send() ничего не делают
  },
})

Опции конфига состояния ​

on ​

Record<TEvent, TransitionConfig>. Обработчики событий.

entry ​

Action[]. Вызывается при входе машины в это состояние.

exit ​

Action[]. Вызывается при выходе машины из этого состояния.

type ​

'final'. Терминальное состояние — isDone становится true, send() игнорируется.

parallel ​

Record<string, SubMachineConfig>. Параллельные регионы — см. Параллельные состояния.

Опции конфига перехода ​

target ​

TState. Целевое состояние (проверяется TypeScript'ом против конфига).

guard ​

Guard<TContext, TEvent>. Синхронный предикат; false или выброшенное исключение блокирует переход.

actions ​

Action<TContext, TEvent>[]. Побочные эффекты, выполняемые во время перехода.

Валидация в dev-режиме ​

В режиме разработки (import.meta.env.DEV !== false) defineMachine выбрасывает содержательные ошибки для:

  • Пустого config.id
  • initial, не найденного в states
  • Любого target, ссылающегося на несуществующее состояние

Валидация удаляется tree-shaking'ом в продакшен-сборках.

Guards и Actions ​

ts
type Guard<TContext, TEvent> = (context: TContext, event: EventObject<TEvent>) => boolean

type Action<TContext, TEvent> = (
  context: TContext,
  event: EventObject<TEvent>,
) => void | Partial<TContext> | Promise<Partial<TContext> | void>

Правила для guard:

  • Должен быть синхронным и без побочных эффектов — также вызывается реактивно из can()
  • Исключение внутри guard перехватывается и трактуется как false
  • Возвращаемые значения Promise не ожидаются — используйте actions для асинхронной работы

Правила для action:

  • Может быть async — очередь событий ожидает каждый action перед выполнением следующего
  • Верните Partial<TContext>, чтобы слить обновления в контекст; верните void только для побочных эффектов
  • Actions выполняются по порядку: exit → transition.actions → entry
ts
// Action, обновляющий контекст
const incrementAttempts = (ctx: { attempts: number }) => ({
  attempts: ctx.attempts + 1,
})

// Асинхронный action — результат fetch сливается в контекст
const loadUser = async (ctx, event: { type: 'LOAD'; id: number }) => {
  const user = await api.getUser(event.id)
  return { user }
}

// Guard
const canRetry = (ctx: { attempts: number }) => ctx.attempts < 3