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'

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

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


  1. justboris
    07.11.2016 01:33
    +1

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


    1. jsfun
      07.11.2016 01:56
      +1

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


  1. justboris
    07.11.2016 01:38
    +3

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


    import {StateMachine, StateEvent} from 'angular2-state-machine';


    1. jsfun
      07.11.2016 01:59
      +1

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


  1. Anarions
    07.11.2016 12:50

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


    1. jsfun
      07.11.2016 13:01

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


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


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

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


  1. Captcha
    07.11.2016 15:34

    Чем лучше той же machina.js?


    1. jsfun
      07.11.2016 18:16

      Ничем — делает абсолютно тоже, только написано на TypeScript. State-machine всегда выполняет одно и тоже — будет присутствовать только небольшая разница в имплементации — и все. В данном случае — бонус для TypeScript любителей.