[JavaScript, VueJS] Используем XSTATE для VueJS
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
Маленький пример применения библиотеки XState от David Khourshid для декларативного описания логики компонента VueJS 2. XState это очень развитая библиотека для создания и использования конечных автоматов (КА) на JS. Неплохое подспорье в трудном деле создания веб приложений.
Предистория
В моей прошлой статье кратко описано зачем нужны машины состояний (конечные автоматы) и приведена простенькая реализация для работы с Vue. В моем велосипеде были только состояния и декларация состояний выглядела так:
{
idle: ['waitingConfirmation'],
waitingConfirmation: ['idle','waitingData'],
waitingData: ['dataReady', 'dataProblem'],
dataReady: [‘idle’],
dataProblem: ['idle']
}
По сути это было перечисление состояний и для каждого описан массив возможных состояний, в которые может перейти система. Приложение просто “говорит” машине состояний — хочу перейти в такое состояние, если это возможно машина переходит в нужное состояние.
Этот подход работает, но возникают неудобства. Например если кнопка в разном состоянии должна инициировать переход в разные состояния. Придется городить условия. Вместо декларативности получаем кашу.
Изучив теорию по роликам из Ютюба, стало понятно, что события нужны и важны. В голове родился такой вид декларации:
{
idle: {
GET: 'waitingConfirmation',
},
waitingConfirmation: {
CANCEL: 'idle',
CONFIRM: 'waitingData'
},
waitingData: {
SUCCESS: 'dataReady',
FAILURE: 'dataProblem'
},
dataReady: {
REPEAT: 'idle'
},
dataProblem: {
REPEAT: 'idle'
}
}
А это уже очень напоминает то, как описывает состояния библиотека XState. Почитав внимательней доку, я решил убрать самодельный велосипед в сарай, и пересесть на фирменный.
VUE + XState
Установка очень простая, читайте доку, после установки включаем XState в компонент:
import {Machine, interpret} from ‘xstate’
Создаем машину на основе объекта-декларации:
const myMachine = Machine({
id: 'myMachineID',
context: {
/* some data */
},
initial: 'idle',
states: {
idle: {
on: {
GET: 'waitingConfirmation',
}
},
waitingConfirmation: {
on: {
CANCEL: 'idle',
CONFIRM: 'waitingData'
}
},
waitingData: {
on: {
SUCCESS: 'dataReady',
FAILURE: 'dataProblem'
},
},
dataReady: {
on: {
REPEAT: 'idle'
}
},
dataProblem: {
on: {
REPEAT: 'idle'
}
}
}
})
Понятно, что есть состояния ‘idle’, ‘’waitingConfirmation' … и есть события в верхнем регистре GET, CANCEL, CONFIRM ….
Сама по себе машина не работает, из нее надо создать сервис с помощью функции interpret. Ссылку на этот сервис разместим в наш state, а заодно и ссылку на текущее состояние current:
data: {
toggleService: interpret(myMachine),
current: myMachine.initialState,
}
Сервис надо стартануть — start(), а также указать, что при переходах состояния мы обновляем значение current:
mounted() {
this.toggleService
.onTransition(state => {
this.current = state
})
.start();
}
В методы добавляем функцию send, ее и используем для управления машиной — передачи ей событий:
methods: {
send(event) {
this.toggleService.send(event);
},
…
}
Ну а дальше все просто. Передавать событие просто вызовом:
this.send(‘SUCCESS’)
Узнать текущее состояние:
this.current.value
Проверить нахождение машины в определенном состоянии так:
this.current.matches(‘waitingData')
Cоберем все вместе:
Template
SPL
<div id="app">
<h2>XState machine with Vue</h2>
<div class="panel">
<div v-if="current.matches('idle')">
<button @click="send('GET')">
<span>Get data</span>
</button>
</div>
<div v-if="current.matches('waitingConfirmation')">
<button @click="send('CANCEL')">
<span>Cancel</span>
</button>
<button @click="getData">
<span>Confirm get data</span>
</button>
</div>
<div v-if="current.matches('waitingData')" class="blink_me">
loading ...
</div>
<div v-if="current.matches('dataReady')">
<div class='data-hoder'>
{{ text }}
</div>
<div>
<button @click="send('REPEAT')">
<span>Back</span>
</button>
</div>
</div>
<div v-if="current.matches('dataProblem')">
<div class='data-hoder'>
Data error!
</div>
<div>
<button @click="send('REPEAT')">
<span>Back</span>
</button>
</div>
</div>
</div>
<div class="state">
Current state: <span class="state-value">{{ current.value }}</span>
</div>
</div>
JS
SPL
const { Machine, interpret } = XState
const myMachine = Machine({
id: 'myMachineID',
context: {
/* some data */
},
initial: 'idle',
states: {
idle: {
on: {
GET: 'waitingConfirmation',
}
},
waitingConfirmation: {
on: {
CANCEL: 'idle',
CONFIRM: 'waitingData'
}
},
waitingData: {
on: {
SUCCESS: 'dataReady',
FAILURE: 'dataProblem'
},
},
dataReady: {
on: {
REPEAT: 'idle'
}
},
dataProblem: {
on: {
REPEAT: 'idle'
}
}
}
})
new Vue({
el: "#app",
data: {
text: '',
toggleService: interpret(myMachine),
current: myMachine.initialState,
},
computed: {
},
mounted() {
this.toggleService
.onTransition(state => {
this.current = state
})
.start();
},
methods: {
send(event) {
this.toggleService.send(event);
},
getData() {
this.send('CONFIRM')
requestMock()
.then((data) => {
this.text = data.text
this.send('SUCCESS')
})
.catch(() => this.send('FAILURE'))
},
}
})
function randomInteger(min, max) {
let rand = min + Math.random() * (max + 1 - min)
return Math.floor(rand);
}
function requestMock() {
return new Promise((resolve, reject) => {
const randomValue = randomInteger(1,2)
if(randomValue === 2) {
let data = { text: 'Data received!!!'}
setTimeout(resolve, 3000, data)
}
else {
setTimeout(reject, 3000)
}
})
}
Ну и конечно все это можно потрогать на jsfiddle.net
Visualizer
XState предоставляет замечательный инструмент — Visualizer. Можно посмотреть диаграмму именно вашей машины. И не только посмотреть но и пощелкать по событиям и осуществить переходы. Вот так выглядит наш пример:
Итог
XState отлично работает, вместе с VueJS. Это упрощает работу компонента, позволяет избавиться от лишнего кода. Главное — декларация машины позволяет быстро понять логику. Данный пример простой, но я уже пробовал и на более сложном примере для рабочего проекта. Полет нормальный.
В данной статье я использовал только самый базовый функционал библиотеки, так как мне его пока хватает, но библиотека содержит еще массу интересный возможностей:
- Guarded transitions
- Actions (entry, exit, transition)
- Extended state (context)
- Orthogonal (parallel) states
- Hierarchical (nested) states
- History
А есть еще аналогичные библиотеки, например Robot. Вот сравнение Comparing state machines: XState vs. Robot. Так что если вас заинтересовала тема, вам будет чем заняться.
===========
Источник:
habr.com
===========
Похожие новости:
- [CMS, JavaScript, Разработка веб-сайтов, Хостинг] От небольшого вики-портала до хостинга
- [Карьера в IT-индустрии] Как НЕ надо начинать изучать программирование
- [JavaScript, Node.JS, Программирование, Разработка веб-сайтов] Руководство по Express.js. Часть 3 (перевод)
- [JavaScript, ReactJS, Программирование] Почему я разочаровался в хуках (перевод)
- [C++, Программирование] Антипаттерн “константа размера массива” (перевод)
- [VueJS, Magento] Введение во Vue Storefront (перевод)
- [JavaScript, Программирование, Браузеры, Стандарты связи] (Почти) бесполезный стриминг вебкамеры из браузера. Часть 2. WebRTC
- [JavaScript, ReactJS, VueJS] Микросервисы во фронтенде
- [JavaScript, Node.JS, Разработка веб-сайтов] Компоновщик в JavaScript (перевод)
- [JavaScript, Профессиональная литература] TypeScript. Продвинутые типы
Теги для поиска: #_javascript, #_vuejs, #_vue, #_vuejs2, #_vuejs, #_patterns, #_konechnye_avtomaty (конечные автоматы), #_mashina_sostojanij (машина состояний), #_javascript, #_javascript, #_vuejs
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 18:19
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
Маленький пример применения библиотеки XState от David Khourshid для декларативного описания логики компонента VueJS 2. XState это очень развитая библиотека для создания и использования конечных автоматов (КА) на JS. Неплохое подспорье в трудном деле создания веб приложений. Предистория В моей прошлой статье кратко описано зачем нужны машины состояний (конечные автоматы) и приведена простенькая реализация для работы с Vue. В моем велосипеде были только состояния и декларация состояний выглядела так: {
idle: ['waitingConfirmation'], waitingConfirmation: ['idle','waitingData'], waitingData: ['dataReady', 'dataProblem'], dataReady: [‘idle’], dataProblem: ['idle'] } По сути это было перечисление состояний и для каждого описан массив возможных состояний, в которые может перейти система. Приложение просто “говорит” машине состояний — хочу перейти в такое состояние, если это возможно машина переходит в нужное состояние. Этот подход работает, но возникают неудобства. Например если кнопка в разном состоянии должна инициировать переход в разные состояния. Придется городить условия. Вместо декларативности получаем кашу. Изучив теорию по роликам из Ютюба, стало понятно, что события нужны и важны. В голове родился такой вид декларации: {
idle: { GET: 'waitingConfirmation', }, waitingConfirmation: { CANCEL: 'idle', CONFIRM: 'waitingData' }, waitingData: { SUCCESS: 'dataReady', FAILURE: 'dataProblem' }, dataReady: { REPEAT: 'idle' }, dataProblem: { REPEAT: 'idle' } } А это уже очень напоминает то, как описывает состояния библиотека XState. Почитав внимательней доку, я решил убрать самодельный велосипед в сарай, и пересесть на фирменный. VUE + XState Установка очень простая, читайте доку, после установки включаем XState в компонент: import {Machine, interpret} from ‘xstate’
Создаем машину на основе объекта-декларации: const myMachine = Machine({
id: 'myMachineID', context: { /* some data */ }, initial: 'idle', states: { idle: { on: { GET: 'waitingConfirmation', } }, waitingConfirmation: { on: { CANCEL: 'idle', CONFIRM: 'waitingData' } }, waitingData: { on: { SUCCESS: 'dataReady', FAILURE: 'dataProblem' }, }, dataReady: { on: { REPEAT: 'idle' } }, dataProblem: { on: { REPEAT: 'idle' } } } }) Понятно, что есть состояния ‘idle’, ‘’waitingConfirmation' … и есть события в верхнем регистре GET, CANCEL, CONFIRM …. Сама по себе машина не работает, из нее надо создать сервис с помощью функции interpret. Ссылку на этот сервис разместим в наш state, а заодно и ссылку на текущее состояние current: data: {
toggleService: interpret(myMachine), current: myMachine.initialState, } Сервис надо стартануть — start(), а также указать, что при переходах состояния мы обновляем значение current: mounted() {
this.toggleService .onTransition(state => { this.current = state }) .start(); } В методы добавляем функцию send, ее и используем для управления машиной — передачи ей событий: methods: {
send(event) { this.toggleService.send(event); }, … } Ну а дальше все просто. Передавать событие просто вызовом: this.send(‘SUCCESS’)
Узнать текущее состояние: this.current.value
Проверить нахождение машины в определенном состоянии так: this.current.matches(‘waitingData')
Cоберем все вместе: TemplateSPL<div id="app">
<h2>XState machine with Vue</h2> <div class="panel"> <div v-if="current.matches('idle')"> <button @click="send('GET')"> <span>Get data</span> </button> </div> <div v-if="current.matches('waitingConfirmation')"> <button @click="send('CANCEL')"> <span>Cancel</span> </button> <button @click="getData"> <span>Confirm get data</span> </button> </div> <div v-if="current.matches('waitingData')" class="blink_me"> loading ... </div> <div v-if="current.matches('dataReady')"> <div class='data-hoder'> {{ text }} </div> <div> <button @click="send('REPEAT')"> <span>Back</span> </button> </div> </div> <div v-if="current.matches('dataProblem')"> <div class='data-hoder'> Data error! </div> <div> <button @click="send('REPEAT')"> <span>Back</span> </button> </div> </div> </div> <div class="state"> Current state: <span class="state-value">{{ current.value }}</span> </div> </div> JSSPLconst { Machine, interpret } = XState
const myMachine = Machine({ id: 'myMachineID', context: { /* some data */ }, initial: 'idle', states: { idle: { on: { GET: 'waitingConfirmation', } }, waitingConfirmation: { on: { CANCEL: 'idle', CONFIRM: 'waitingData' } }, waitingData: { on: { SUCCESS: 'dataReady', FAILURE: 'dataProblem' }, }, dataReady: { on: { REPEAT: 'idle' } }, dataProblem: { on: { REPEAT: 'idle' } } } }) new Vue({ el: "#app", data: { text: '', toggleService: interpret(myMachine), current: myMachine.initialState, }, computed: { }, mounted() { this.toggleService .onTransition(state => { this.current = state }) .start(); }, methods: { send(event) { this.toggleService.send(event); }, getData() { this.send('CONFIRM') requestMock() .then((data) => { this.text = data.text this.send('SUCCESS') }) .catch(() => this.send('FAILURE')) }, } }) function randomInteger(min, max) { let rand = min + Math.random() * (max + 1 - min) return Math.floor(rand); } function requestMock() { return new Promise((resolve, reject) => { const randomValue = randomInteger(1,2) if(randomValue === 2) { let data = { text: 'Data received!!!'} setTimeout(resolve, 3000, data) } else { setTimeout(reject, 3000) } }) } Ну и конечно все это можно потрогать на jsfiddle.net Visualizer XState предоставляет замечательный инструмент — Visualizer. Можно посмотреть диаграмму именно вашей машины. И не только посмотреть но и пощелкать по событиям и осуществить переходы. Вот так выглядит наш пример: Итог XState отлично работает, вместе с VueJS. Это упрощает работу компонента, позволяет избавиться от лишнего кода. Главное — декларация машины позволяет быстро понять логику. Данный пример простой, но я уже пробовал и на более сложном примере для рабочего проекта. Полет нормальный. В данной статье я использовал только самый базовый функционал библиотеки, так как мне его пока хватает, но библиотека содержит еще массу интересный возможностей:
А есть еще аналогичные библиотеки, например Robot. Вот сравнение Comparing state machines: XState vs. Robot. Так что если вас заинтересовала тема, вам будет чем заняться. =========== Источник: habr.com =========== Похожие новости:
|
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 18:19
Часовой пояс: UTC + 5