David Khourshid 使用XState库来声明性地描述VueJS 2组件的逻辑的一个小例子XState是一个非常高级的库,用于在JS中创建和使用状态机。在创建Web应用程序这一艰巨的任务中,这不是一个坏帮助。
史前史
在上一篇文章中,我简要介绍了为什么需要状态机(状态机)以及使用Vue的简单实现。我的自行车只有状态,并且状态声明如下:
{
idle: ['waitingConfirmation'],
waitingConfirmation: ['idle','waitingData'],
waitingData: ['dataReady', 'dataProblem'],
dataReady: [‘idle’],
dataProblem: ['idle']
}
实际上,这是状态的枚举,并且针对每个状态描述了系统可以进入的一系列可能状态。该应用程序只是简单地对状态机“说”-我想进入这种状态,如果可能的话,该机器会进入所需的状态。
此方法有效,但有一些不便之处。例如,如果处于不同状态的按钮应启动到不同状态的转换。在这种情况下,我们必须围栏。与其说声明性,不如说是一团糟。
在研究了有关YouTube视频的理论之后,很明显事件是必要且重要的。这种宣言诞生于我的脑海:
{
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 ...中的事件。
机器本身不工作,您需要使用解释功能从中创建服务。我们将在我们的状态下放置一个指向该服务的链接,同时在当前状态下放置一个链接:
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')
放在一起:
模板
<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>
s
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上找到
可视化器
XState提供了一个很棒的工具Visualizer。您可以看到特定汽车的图表。并且不仅要查看事件,还要单击事件并进行转换。这是我们的示例如下所示:
结果
XState可与VueJS完美结合。这简化了组件的工作,并让您摆脱了不必要的代码。最主要的是,机器的声明使您可以快速理解逻辑。这个例子很简单,但是我已经在一个正在运行的项目的更复杂的例子上进行了尝试。飞行正常。
在本文中,由于我仍然拥有足够的功能,因此仅使用了该库的最基本功能,但是该库包含许多更有趣的功能:
- 保护过渡
- 动作(进入,退出,过渡)
- 扩展状态(上下文)
- 正交(平行)状态
- 分层(嵌套)状态
- 历史
还有类似的库,例如Robot。这里是比较状态机的比较:XState与。机器人。因此,如果您对某个主题感兴趣,那么您将有事要做。