Saya percaya bahwa memiliki pemahaman tentang motivasi di balik Mutasi dan Tindakan memungkinkan seseorang untuk menilai dengan lebih baik kapan harus menggunakan mana dan bagaimana. Ini juga membebaskan programmer dari beban ketidakpastian dalam situasi di mana "aturan" menjadi kabur. Setelah beralasan tentang tujuan mereka masing-masing, saya sampai pada kesimpulan bahwa meskipun mungkin ada cara yang salah untuk menggunakan Tindakan dan Mutasi, saya tidak berpikir bahwa ada pendekatan kanonik.
Pertama-tama mari kita mencoba memahami mengapa kita melakukan mutasi atau tindakan.
Mengapa harus melalui boilerplate? Mengapa tidak mengubah status langsung dalam komponen?
Sebenarnya Anda dapat mengubah state
langsung dari komponen Anda. Ini state
hanyalah objek JavaScript dan tidak ada yang ajaib yang akan mengembalikan perubahan yang Anda buat padanya.
// Yes, you can!
this.$store.state['products'].push(product)
Namun, dengan melakukan ini, Anda menyebarkan mutasi negara Anda di semua tempat. Anda kehilangan kemampuan untuk hanya membuka satu modul untuk perumahan negara dan sekilas melihat jenis operasi apa yang dapat diterapkan untuk itu. Setelah mutasi terpusat menyelesaikan ini, meskipun dengan biaya beberapa boilerplate.
// so we go from this
this.$store.state['products'].push(product)
// to this
this.$store.commit('addProduct', {product})
...
// and in store
addProduct(state, {product}){
state.products.push(product)
}
...
Saya pikir jika Anda mengganti sesuatu yang pendek dengan boilerplate, Anda ingin boilerplate juga kecil. Karena itu saya berasumsi bahwa mutasi dimaksudkan untuk menjadi pembungkus yang sangat tipis di sekitar operasi asli di negara bagian, dengan hampir tidak ada logika bisnis. Dengan kata lain, mutasi dimaksudkan untuk sebagian besar digunakan seperti setter.
Sekarang, karena Anda telah memusatkan mutasi Anda, Anda memiliki gambaran yang lebih baik tentang perubahan status Anda dan karena tooling Anda (vue-devtools) juga mengetahui lokasi itu, menjadikan proses debug menjadi lebih mudah. Perlu juga diingat bahwa banyak plugin Vuex tidak menonton negara secara langsung untuk melacak perubahan, mereka lebih mengandalkan mutasi untuk itu. Perubahan-perubahan "tidak terikat" pada negara dengan demikian tidak terlihat oleh mereka.
Jadi mutations
, actions
apa bedanya sih?
Tindakan, seperti mutasi, juga berada di modul toko dan dapat menerima state
objek. Yang menyiratkan bahwa mereka juga bisa bermutasi secara langsung. Jadi apa gunanya memiliki keduanya? Jika kita beralasan bahwa mutasi harus dijaga tetap kecil dan sederhana, itu menyiratkan bahwa kita memerlukan sarana alternatif untuk menampung logika bisnis yang lebih rumit. Tindakan adalah cara untuk melakukan ini. Dan karena seperti yang telah kita ketahui sebelumnya, vue-devtools dan plugins menyadari perubahan melalui Mutasi, agar tetap konsisten kita harus terus menggunakan Mutasi dari tindakan kita. Lebih jauh, karena tindakan dimaksudkan untuk mencakup semua dan bahwa logika yang mereka enkapsulasi mungkin tidak sinkron, maka masuk akal jika Tindakan juga akan dibuat tidak sinkron sejak awal.
Sering ditekankan bahwa tindakan bisa tidak sinkron, sedangkan mutasi biasanya tidak. Anda dapat memutuskan untuk melihat perbedaan sebagai indikasi bahwa mutasi harus digunakan untuk apa pun yang sinkron (dan tindakan untuk apa pun yang tidak sinkron); Namun, Anda akan mengalami beberapa kesulitan jika misalnya Anda perlu melakukan lebih dari satu mutasi (secara serempak), atau jika Anda perlu bekerja dengan Getter dari mutasi Anda, karena fungsi mutasi tidak menerima Getters atau Mutations sebagai argumen ...
... yang mengarah ke pertanyaan menarik.
Mengapa Mutasi tidak menerima Getters?
Saya belum menemukan jawaban yang memuaskan untuk pertanyaan ini. Saya telah melihat beberapa penjelasan oleh tim inti yang saya temukan terbaik diperdebatkan. Jika saya merangkum penggunaannya, Getters dimaksudkan untuk dihitung (dan sering di-cache) ekstensi ke status. Dengan kata lain, mereka pada dasarnya masih keadaan, meskipun itu memerlukan beberapa perhitungan dimuka dan mereka biasanya hanya baca. Setidaknya itulah cara mereka didorong untuk digunakan.
Dengan demikian, mencegah Mutasi dari mengakses langsung Getters berarti bahwa satu dari tiga hal sekarang diperlukan, jika kita perlu mengakses dari yang sebelumnya beberapa fungsi yang ditawarkan oleh yang terakhir: (1) salah satu perhitungan keadaan yang disediakan oleh Getter digandakan di suatu tempat yang dapat diakses ke Mutasi (bau tak sedap), atau (2) nilai yang dihitung (atau Getter yang relevan itu sendiri) diturunkan sebagai argumen eksplisit terhadap Mutasi (funky), atau (3) logika Getter sendiri digandakan langsung dalam Mutasi , tanpa manfaat tambahan dari caching seperti yang diberikan oleh Getter (bau busuk).
Berikut ini adalah contoh (2), yang dalam kebanyakan skenario yang saya temui tampaknya merupakan opsi "paling buruk".
state:{
shoppingCart: {
products: []
}
},
getters:{
hasProduct(state){
return function(product) { ... }
}
}
actions: {
addProduct({state, getters, commit, dispatch}, {product}){
// all kinds of business logic goes here
// then pull out some computed state
const hasProduct = getters.hasProduct(product)
// and pass it to the mutation
commit('addProduct', {product, hasProduct})
}
}
mutations: {
addProduct(state, {product, hasProduct}){
if (hasProduct){
// mutate the state one way
} else {
// mutate the state another way
}
}
}
Bagi saya, di atas tampaknya tidak hanya sedikit berbelit-belit, tetapi juga agak "bocor", karena beberapa kode yang ada dalam Aksi jelas mengalir dari logika internal Mutasi.
Menurut pendapat saya, ini merupakan indikasi kompromi. Saya percaya bahwa memungkinkan Mutasi untuk secara otomatis menerima Getters menghadirkan beberapa tantangan. Ini dapat berupa desain Vuex sendiri, atau tooling (vue-devtools et al), atau untuk mempertahankan beberapa kompatibilitas, atau kombinasi dari semua kemungkinan yang dinyatakan.
Apa yang saya tidak percaya adalah bahwa menyerahkan Surat kepada Mutasi Anda sendiri adalah pertanda bahwa Anda melakukan sesuatu yang salah. Saya melihatnya hanya sebagai "menambal" salah satu kelemahan kerangka kerja.