Пейджер

Одно или много событий у состояния

Одно или много событий у состояния

Если у вас есть нагрузка у событий и/или контекст, то можно сделать единственное событие на все состояния, которое будет выбирать следующее состояние на основе имеющихся данных. Такой вариант уже не совсем чистая fsm и он чуть ближе к редьюсеру, но он может быть удобен, если нужно, чтобы fsm работала в автоматическом режиме

const stateMachine = {
  currentState: 'untouched',
  context: {
    value: '',
  },

  setContext(patch) {
    this.context = { ...this.context, ...patch };
  },

  next(payload) {
    const action = this[this.currentState];

    if (!action) throw new Error();

    this.currentState = action(
      this.context,
      (patch) => this.setContext(patch),
      payload,
    );
  },

  untouched(context, setContext, value) {
    setContext({ value });
    return value.length > 3 ? 'valid' : 'error';
  },
  error: (context, setContext, value) => {
    setContext({ value: '' });

    if (!value) return 'untouched';
    if (value.length > 3) return 'valid';
    return 'error';
  },
  valid() {
    /*  */
  },
};

stateMachine.next('hi');
console.log(stateMachine.currentState); // error
console.log(stateMachine.context); // { value: 'hi' }
stateMachine.next();
console.log(stateMachine.currentState); // untouched
console.log(stateMachine.context); // { value: '' }


Далее хотелось бы отметить несколько возможностей по работе со стейт машинами

В зависимости от задачи запуск событий стейт машины может выполняться в ручном, автоматическом или комбинированном режимах

Правилом перехода для состояния может служить другая стейт машина, которая запускается при переходе и результат ее выполнения определяет следующее состояние

Конечно же fsm можно типизировать, тут типизация опущена только чтобы упростить примеры

По желанию, за счет конечного автомата можно разделять сами процессы и реагирование на этапы, если реализовать, например, подписку на изменение состояния

stateMachine.subscribe((state, context) => {
  if (state === 'unknownError') {
    history.pushState({}, null, '/500');
  }

  if (context.someValue) {
    sendMetrics();
  }
});


Написать реализацию стейт машины под свои нужны не будет сложно, но если нужен какой-то готовый и универсальный инструмент, то есть xstate. У них есть и примеры использования, которые можно посмотреть в отрыве от реализации
Хотите больше таких постов?
Подпишитесь на канал и читайте продолжение в Telegram.
Подписаться на @typescript_bowl Открыть пост в Telegram