Contoh kecil penggunaan pustaka XState oleh David Khourshid untuk mendeskripsikan logika komponen VueJS 2. XState adalah pustaka yang sangat canggih untuk membuat dan menggunakan mesin negara di JS. Bukan bantuan yang buruk dalam tugas sulit membuat aplikasi web.
Prasejarah
Dalam artikel terakhir saya , saya menjelaskan secara singkat mengapa mesin negara (mesin negara) diperlukan dan implementasi sederhana untuk bekerja dengan Vue. Sepeda saya hanya memiliki status dan pernyataan negara terlihat seperti ini:
{
idle: ['waitingConfirmation'],
waitingConfirmation: ['idle','waitingData'],
waitingData: ['dataReady', 'dataProblem'],
dataReady: [‘idle’],
dataProblem: ['idle']
}
Faktanya, itu adalah pencacahan negara bagian, dan untuk setiap larik kemungkinan negara bagian yang dapat dituju sistem dijelaskan. Aplikasi hanya "mengatakan" ke mesin negara - Saya ingin masuk ke keadaan seperti itu, jika memungkinkan, mesin masuk ke keadaan yang diinginkan.
Pendekatan ini berhasil, tetapi ada ketidaknyamanan. Misalnya, jika tombol dalam keadaan berbeda harus memulai transisi ke keadaan berbeda. Kami harus memagari kondisi. Alih-alih menjadi deklaratif, kita malah menjadi berantakan.
Setelah mempelajari teori tentang video dari YouTube, menjadi jelas bahwa peristiwa itu perlu dan penting. Pernyataan semacam ini lahir di kepala saya:
{
idle: {
GET: 'waitingConfirmation',
},
waitingConfirmation: {
CANCEL: 'idle',
CONFIRM: 'waitingData'
},
waitingData: {
SUCCESS: 'dataReady',
FAILURE: 'dataProblem'
},
dataReady: {
REPEAT: 'idle'
},
dataProblem: {
REPEAT: 'idle'
}
}
Dan ini sudah sangat mirip dengan bagaimana perpustakaan XState mendeskripsikan status. Setelah membaca dok lebih teliti, saya memutuskan untuk meletakkan sepeda buatan saya di gudang dan beralih ke sepeda bermerek.
VUE + XState
Instalasi sangat sederhana, baca dokumennya, setelah instalasi kami memasukkan XState ke dalam komponen:
import {Machine, interpret} from ‘xstate’
Kami membuat mobil berdasarkan objek deklarasi:
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'
}
}
}
})
Jelas bahwa ada status 'idle', 'waitingConfirmation' ... dan ada event dalam huruf besar GET, CANCEL, CONFIRM….
Mesin itu sendiri tidak berfungsi, Anda perlu membuat layanan darinya menggunakan fungsi interpret. Kami akan menempatkan tautan ke layanan ini di negara bagian kami, dan pada saat yang sama tautan ke status saat ini:
data: {
toggleService: interpret(myMachine),
current: myMachine.initialState,
}
Layanan harus dimulai - start (), dan juga menunjukkan bahwa ketika transisi status, kami memperbarui nilai saat ini:
mounted() {
this.toggleService
.onTransition(state => {
this.current = state
})
.start();
}
Kami menambahkan fungsi kirim ke metode, dan menggunakannya untuk mengontrol mesin - untuk mengirim acara ke sana:
methods: {
send(event) {
this.toggleService.send(event);
},
…
}
Nah, kalau begitu semuanya sederhana. Kirim acara hanya dengan menelepon:
this.send(‘SUCCESS’)
Cari tahu keadaan saat ini:
this.current.value
Periksa apakah mesin dalam kondisi tertentu sebagai berikut:
this.current.matches(‘waitingData')
Menyatukan semuanya:
Template
<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)
}
})
}
Dan tentunya semua ini bisa disentuh di jsfiddle.net
Visualizer
XState menyediakan alat yang hebat, Visualizer . Anda dapat melihat diagram mobil khusus Anda. Dan tidak hanya untuk melihat tetapi juga untuk mengklik peristiwa dan melakukan transisi. Seperti inilah contoh kita:
Hasil
XState bekerja sangat baik dengan VueJS. Ini menyederhanakan pekerjaan komponen dan memungkinkan Anda membuang kode yang tidak perlu. Hal utama adalah bahwa deklarasi mesin memungkinkan Anda untuk memahami logika dengan cepat. Contoh ini sederhana, tetapi saya sudah mencobanya pada contoh yang lebih kompleks untuk sebuah proyek kerja. Penerbangannya normal.
Dalam artikel ini, saya hanya menggunakan fungsionalitas paling dasar dari pustaka, karena saya masih memiliki cukup banyak, tetapi pustaka berisi lebih banyak fitur menarik:
- Transisi yang dijaga
- Tindakan (masuk, keluar, transisi)
- Status yang diperluas (konteks)
- Keadaan ortogonal (paralel)
- Status hierarki (bersarang)
- Sejarah
Dan ada juga library yang serupa, contohnya Robot. Berikut perbandingan membandingkan mesin negara: XState vs. Robot . Jadi, jika Anda tertarik dengan suatu topik, ada sesuatu yang harus Anda lakukan.