Пейджер

Далее есть набор возможных модификаций:

Далее есть набор возможных модификаций:

С нагрузкой при переходах и без

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

const stateMachine = {
  currentState: 'untouched',

  run(eventName, payload) {
    const transition = this[this.currentState][eventName];

    if (!transition) throw new Error();

    this.currentState = transition(payload);
  },

  untouched: {
    validate: (payload) => (payload.length > 3 ? 'valid' : 'error'),
  },
  error: {
    clear: () => 'untouched',
  },
};

stateMachine.run('validate', 'hi');
console.log(stateMachine.currentState); // error
stateMachine.run('clear');
console.log(stateMachine.currentState); // untouched
stateMachine.run('validate', 'hello');
console.log(stateMachine.currentState); // valid


Теперь переход является не просто мапингом из события в новое состояние, а это метод с дополнительной логикой, опирающейся на передаваемые данные

С дополнительным контекстом (Extended State Machine) и без

У стейт машины может быть дополнительный внутренний контекст, который модифицируется при переходах и/или извне и который может влиять на то, каким будет следующие состояние

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

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

  run(eventName) {
    const transition = this[this.currentState][eventName];

    if (!transition) throw new Error();

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

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

stateMachine.setContext({ value: 'hi' });
stateMachine.run('validate');
console.log(stateMachine.currentState); // error
console.log(stateMachine.context); // { value: 'hi' }
stateMachine.run('clear');
console.log(stateMachine.currentState); // untouched
console.log(stateMachine.context); // { value: '' }


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