State machines для сложного UI: finite states и XState

↑ 8.2 Архитектура фронтенда и паттерны · ← Предыдущая · → Следующая

Желательно~3 мин чтенияУровень: senior

Зачем это на собесе

Показывает умение моделировать сложные сценарии (формы, мастеры, загрузка) без комбинаторики булевых флагов.

Проблема булевых флагов

const isLoading = ref(false), isError = ref(false), isSuccess = ref(false)
// возможны невозможные состояния: isLoading && isSuccess

Конечный автомат

Состояний конечное число; в каждый момент активно одно; переходы происходят по событиям; недопустимые переходы игнорируются.

import { createMachine, assign } from 'xstate'
 
export const fetchMachine = createMachine({
  id: 'fetch',
  initial: 'idle',
  context: { data: null as Data | null, error: null as string | null, retries: 0 },
  states: {
    idle: { on: { FETCH: 'loading' } },
    loading: {
      invoke: {
        src: 'load',
        onDone: { target: 'success', actions: assign({ data: ({ event }) => event.output }) },
        onError: { target: 'failure', actions: assign({ error: ({ event }) => String(event.error) }) },
      },
    },
    success: { on: { FETCH: 'loading' } },
    failure: { on: { RETRY: { target: 'loading', guard: ({ context }) => context.retries < 3 } } },
  },
})

Понятия XState

  • состояния, события, переходы;
  • context — расширенное данные;
  • guards — условия переходов;
  • actions — побочные эффекты при переходе;
  • invoke / actors — асинхронные задачи;
  • иерархические и параллельные состояния;
  • statechart — расширенная модель Харела.

Применение во Vue

import { useMachine } from '@xstate/vue'
const { snapshot, send } = useMachine(fetchMachine)
// snapshot.value.matches('loading'), send({ type: 'FETCH' })

Где полезно

Многошаговые формы (мастера), оплата, загрузка файлов с прогрессом, аутентификация, редакторы, drag-and-drop. Визуализатор (Stately) и модель для тестирования.

Когда избыточно

Простые переключатели и простая загрузка. Для небольших задач достаточно status: 'idle' | 'loading' | 'success' | 'error' — минимальная «машина» на union-типе.

Вопросы с ответами