- PVSM.RU - https://www.pvsm.ru -

Простая машина состояний для VueJS

Простая машина состояний для VueJS - 1

Недавно я наткнулся на интересное обсуждение на Full Stack Radio — Bulding Better UI Components with State Machines [1]. Речь шла о том, что концепция машины состояний может помочь при разработке компонентов Vue. Я начал просматривать готовые решения, но они оказались не столь просты, и мне захотелось сделать более простую реализацию, о которой я и хочу рассказать в этой статье. Статья может оказаться полезной не только для тех кто использует Vue, но и для пользователей Angular, React и т.д., а также для программистов других «конфессий».

В обсуждении затрагивалась тема, близкая всем, кто писал компоненты. Представьте. что вы пишете компонент, который обращается за данными, и вам надо отобразить спиннер на то время, пока запрос выполняется. Обычно в таких случаях вы создаете логическую переменную isLoading. Изначально isLoading = false, а перед тем, как запросить данные вы присваиваете переменной isLoading значение true. После того, как данные пришли вы опять присваиваете ей значение false. Видимость спиннера привязана к isLoading.

Этот подход отлично работает. Но компонент редко бывает столь простым. И в ходе работы приходится создавать еще логические переменные, которые хранят разные состояния. Проблема в том, что если у вас одна переменная состояния, она порождает два состояния, а две логические переменные уже четыре состояния, три — восемь и т.д. И беда в том, программист может ошибиться и не обработать какие-то состояния, в которые может прийти система. А это приводит к ошибке. Кроме того довольно сложно понимать такой компонент и приходится плодить условия.

Ответ — машина состояний. Принцип простой — вы описываете состояния в которых может быть система, и переходы между состояниями. Имея такую машину можно избежать многих ошибок, а также декларативно определять состояния системы.

На эту тему довольно много статей (например Finite State Machines in Vue [2], но большинство из них после краткой теории рекомендуют подключить одну из готовых библиотек. Например davidkpiano/xstate [3].

Мне xstate показался излишне громоздким и захотелось попробовать свой велосипед. К тому же это отличный повод разобрать новый, для меня, паттерн.

Вот тут код с которым можно поиграть — State machine with Vue, version 2 [4]. А тут сырая версия, со слегка отличающимся подходом — State machine with Vue, version 1 [5].
Отталкивался я от статьи State Machines [6].

Итак машина состояний:

class StateMachine {
    constructor (initialState, transitions) {
        this.state = initialState
        this.transitions = transitions
    }
    transition (nextState, method, params) {
  	const transitionsArray = this.transitions[this.state]	
        if(transitionsArray.indexOf(nextState) === -1) return this.state
        if(method) method(...params)
        this.state = nextState
        return this.state
    }
}

Инициализируем ее так:

const machine = new StateMachine('idle', {
    idle: ['waitingConfirmation'],
    waitingConfirmation: ['idle','waitingData'],
    waitingData: ['dataReady', 'dataProblem'],
    dataReady: ['waitingConfirmation'],
    dataProblem: ['waitingConfirmation']
})

В методах компонента создаем функцию перехода:

transition(nextState, method = null, params = []) {
    this.machineState = machine.transition(nextState, method, params)
}

В событиях сразу пишем куда хотим перейти:

@click=“transition('waitingConfirmation')"

Если надо при этом вызвать метод компонента пишем так:

@click="transition('waitingData', getData, [222])”

Второй параметр — метод компонента который надо вызвать с этим переходом.
Третий параметр — массив переменных для этого метода.

Внутри методов вызов такой:

this.transition('dataReady')

Я специально не стал скрывать кнопки с помощью v-if, просто пока делаю цвет их шрифта сереньким. Зато видно, что нажатие на них не срабатывает, если машина не разрешает.

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

Автор: Almatyn

Источник [7]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/javascript/341467

Ссылки в тексте:

[1] Bulding Better UI Components with State Machines: http://www.fullstackradio.com/130

[2] Finite State Machines in Vue: https://www.phillipparker.io/articles/finite-state-machines-in-vue

[3] davidkpiano/xstate: https://github.com/davidkpiano/xstate

[4] State machine with Vue, version 2: https://jsfiddle.net/Rollroll/hwau3zj7/

[5] State machine with Vue, version 1: https://jsfiddle.net/Rollroll/qtw16rdn/

[6] State Machines: https://choo.io/docs/state-machines/

[7] Источник: https://habr.com/ru/post/482250/?utm_source=habrahabr&utm_medium=rss&utm_campaign=482250