Be King of your state with Angular2 State Machine

image

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

Сегодня я хотел бы рассказать об одном интересном open-source проекте, который может облегчить работу с состояниями для тех, кто решил написать или переписать свое приложение на Angular2 и думает о том, переписывать ли ему логику управления состояниями заново или стоит что-либо поискать на просторах этих ваших интернетов.

Angular2 State Machine

angular2-state-machine — это порт, с некоторыми адаптационными изменениями, javascript-state-machine на Angular2 для того, чтобы упростить переход на ng2 тех приложений, которые, так или иначе, работают с состояниями.

На данный момент существует версия на TypeScript, поскольку он, де-факто, является стандартом для ng2 приложений на данный момент.
Сама библиотека простая и небольшая, участие — приветствуется, недавно был выпущен первый релиз в npm.

Немножко кода


Установим библиотеку:
npm i angular2-state-machine --save

Дальше будем исходить из того, что у Вас уже есть рабочее ng2 приложение, пусть даже пустое, с app.component.ts.
Будем рассматривать возможности библиотеки на примере обычного светофора.

Перед тем, как начать использовать библиотеку, надо заимпортить модуль и создать саму state-machine со всеми состояниями и переходами и задать начальное состояние.

import {StateMachine, StateEvent} from './core';

let fsm = new StateMachine({
    initial: 'green',
    events: [
        new StateEvent({
            name: 'toGreen', from: ['yellow'], to: 'green'
        }),
        new StateEvent({
            name: 'toRed', from: ['yellow'], to: 'red'
        }),
        new StateEvent({
            name: 'toYellow', from: ['red', 'green'], to: 'yellow'
        })
    ]
});

Здесь мы создали state-machine на основе трех состояний светофора: Зеленый, Желтый, Красный, и дали имена самим переходам на эти состояния: 'toGreen', 'toYellow', 'toRed'.

Необходимо использовать только уникальные имена событий, иначе сервис на этапе инициализации будет выдавать ошибку: «You have to use unique names for all events».

Перед тем, как идти дальше, нужно обьяснить в двух словах, что такое StateMachine и StateEvent.
StateMachine — собственно, сам сервис, который занимается переходами из состояния в состояние.
StateEvent — типизированное событие, которое описывает переходы в state-machine.

Допустим, Ваше приложение начинается с того, что запускается зеленый свет. Спустя некоторое время, должен запуститься желтый. Для того, чтобы сменить состояние светофора, необходимо сделать следующее:

fsm.fireAction('toYellow'); // Текущее состояние - Желтый свет

Также, можно узнать текущее состояние:

fsm.getCurrent() // yellow

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

fsm.can('toYellow') // Error 'You cannot switch to this state'

В описанном примере Вы не можете переключить на желтый свет, потому как он уже горит.

Есть и инвертированный метод, для любителей:

fsm.cannot('toYellow') // true

Также можно узнать все доступные события указанной машины состояний:

fsm.getEvents() /*  [StateEvent({
            name: 'toGreen', from: ['yellow'], to: 'green'
        }),
        StateEvent({
            name: 'toRed', from: ['yellow'], to: 'red'
        }),
        StateEvent({
            name: 'toYellow', from: ['red', 'green'], to: 'yellow'
        })
    ]*/

Или же узнать текущее имя события на которое переход доступен:

fsm.getTransitions() // 'toYellow'

Если необходимо перейти на шаг назад:

fsm.goToPreviousState() // 'green'

Вот так вот, легко и просто, можно управлять состояниями своего приложения и не переписывать все с нуля.

Комментарии (6)

  • 7 ноября 2016 в 01:33

    0

    А причем здесь Angular2?
    Как видно из кода, библиотека работает с любым фреймворком, разве что больше типизации за счет TypeScript появилось.

    • 7 ноября 2016 в 01:56

      0

      Изначально, я разрабатывал ее под Angular2, но она действительно достаточно проста, чтобы ее переиспользовать

  • 7 ноября 2016 в 01:38

    +1

    Также, было бы неплохо оформить саму библиотеку лучше:
    1) Добавить служебные файлы и папки .idea, .iml, .DS_Store в .gitignore
    2) Убрать peerDependencies из package.json. Они не используются в коде, а значит, не нужны.
    3) Секции main и typings из package.json ведут на несуществующие файлы. Если правильно их описать, то подключать библиотеку станет чуть проще.


    import {StateMachine, StateEvent} from 'angular2-state-machine';
    • 7 ноября 2016 в 01:59

      0

      Согласен, надо убрать и упростить, работаем над этим, спасибо за комментарий.

  • 7 ноября 2016 в 12:50

    0

    Не специализируюсь на фронте, поэтому может глупость спрошу, но вроде-бы есть redux для работы со state-ом? У него ещё и плюшек всяких много.
    • 7 ноября 2016 в 13:01 (комментарий был изменён)

      0

      Redux — управление состоянием всего приложения используя лишь один основной Store + определенное количество reducers, которые state меняют и actions, которые что-то делают — например клик юзера по блоку или загрузка данных. Именно это и является имплементацией Flux. Тогда как, моя маленькая библиотечка служит примитивным целям — просто менять состояние простого обьекта и в зависимости от состояния, приложение может что-то делать.


      У Redux есть связи между reducers, Store и actions, тогда как у меня все просто:


      1. Создал машину состояний
      2. Поменял состояние
      3. При изменении, можно заставить приложение как-то на это отреагировать.

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

© Habrahabr.ru