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>
Js
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と。ロボット。したがって、トピックに興味がある場合は、何かすることがあります。