Meskipun Vuex dianggap sebagai solusi yang hebat, dan banyak pengembang memilihnya sebagai pustaka manajemen negara utama mereka, mereka berharap mendapatkan lebih banyak fitur di rilis mendatang. Oleh karena itu, sementara Vuex 4 baru saja bersiap untuk dirilis, salah satu pengembangnya, Kia King Ishii (bagian dari tim inti) sudah membagikan rencana untuk versi 5 berikutnya. Perlu dicatat bahwa ini hanya rencana dan beberapa hal dapat berubah, namun, arah utama telah dipilih. Tentang dia akan dibahas.
Dengan munculnya Vue 3 dan API Komposisi , pengembang mulai membuat alternatif sederhana. Misalnya, artikel "Anda Mungkin Tidak Membutuhkan Vuex " mendemonstrasikan cara sederhana, fleksibel, dan andal untuk membuat penyimpanan berdasarkan API Komposisi dalam hubungannya dengan
provide/inject
. Kita dapat berasumsi bahwa ini dan beberapa alternatif lain baik-baik saja untuk aplikasi kecil, tetapi seperti yang sering terjadi, mereka memiliki kekurangan: dokumentasi, komunitas, konvensi penamaan, integrasi, alat pengembang.
Poin terakhir sangat penting. Vue sekarang memiliki ekstensi browser yang bagus untuk membantu pengembangan dan debugging. Membuangnya bisa menjadi pemborosan besar, terutama saat membangun aplikasi besar. Untungnya, ini tidak akan terjadi dengan Vuex 5. Sedangkan untuk pendekatan alternatif, mereka akan berhasil, tetapi mereka tidak akan membawa banyak manfaat seperti solusi resmi. Karena itu, mari kita lihat keuntungan seperti apa yang mereka janjikan kepada kita.
Membuat toko
Sebelum melakukan apa pun dengan sisi, kita perlu membuatnya. Di Vuex 4, terlihat seperti ini:
import { createStore } from 'vuex'
export const counterStore = createStore({
state: {
count: 0
},
getters: {
double (state) {
return state.count * 2
}
},
mutations: {
increment (state) {
state.count++
}
},
actions: {
increment (context) {
context.commit('increment')
}
}
})
Penyimpanan juga terdiri dari 4 bagian: keadaan, tempat data disimpan; getter yang menyediakan status komputasi; mutasi diperlukan untuk mengubah status dan tindakan yang dipanggil di luar penyimpanan untuk melakukan operasi di atasnya. Biasanya, tindakan tidak hanya menyebabkan mutasi (seperti pada contoh), tetapi digunakan untuk melakukan tugas asinkron (karena mutasi harus sinkron ) atau menerapkan logika yang lebih kompleks. Seperti apa Vuex 5 itu?
import { defineStore } from 'vuex'
export const counterStore = defineStore({
name: 'counter',
state() {
return { count: 0 }
},
getters: {
double () {
return this.count * 2
}
},
actions: {
increment () {
this.count++
}
}
})
Hal pertama yang berubah adalah penggantian nama
createStore
menjadi
defineStore
. Beberapa saat kemudian akan jelas mengapa. Selanjutnya, ada parameter
name
untuk menentukan nama toko. Sebelumnya, kita membagi sisi menjadi modul, dan nama modul dalam bentuk objek bernama. Lebih lanjut, modul-modul tersebut didaftarkan di ruang global, itulah sebabnya modul-modul tersebut tidak mandiri dan siap untuk digunakan kembali. Sebagai solusinya, parameter harus digunakan
namespaced
untuk mencegah beberapa modul merespons jenis mutasi dan tindakan yang sama. Saya pikir banyak yang telah menemukan ini, tetapi saya tetap akan menambahkan tautan ke dokumentasi . Sekarang kami tidak memiliki modul, setiap penyimpanan secara default adalah penyimpanan terpisah dan independen.
Setelah menentukan namanya, kita perlu membuatnya menjadi
state
fungsi yang mengembalikan status awal, bukan hanya menyetelnya. Ini sangat mirip dengan tampilannya
data
di komponen. Perubahan juga memengaruhi getter, alih-alih
state
menggunakan fungsi sebagai parameter
this
untuk mengakses data. Pendekatan yang sama diterapkan pada tindakan,
this
bukan
stat
sebagai parameter. Terakhir, dan yang terpenting, mutasi digabungkan dengan game aksi. Kia merayakanbahwa mutasi sering kali menjadi penyetel sederhana, membuatnya bertele-tele, rupanya inilah alasan penghapusan. Dia tidak menyebutkan kemungkinan perubahan status di luar store, misalnya dari komponen. Di sini, kami hanya dapat mengacu pada pola Flux, yang tidak merekomendasikan melakukan hal ini dan mendorong pendekatan perubahan status dari tindakan.
Tambahan: Mereka yang menggunakan API Komposisi untuk membuat komponen akan senang mengetahui bahwa ada cara untuk membuat penyimpanan dengan cara yang sama.
import { ref, computed } from 'vue'
import { defineStore } from 'vuex'
export const counterStore = defineStore('counter', () => {
const count = ref(0)
const double = computed(() => count.value * 2)
function increment () {
count.value++
}
return { count, double, increment }
})
Pada contoh di atas, kami meneruskan nama toko sebagai argumen pertama
defineStore
. Sisanya adalah API Komposisi biasa, dan hasilnya akan sama persis seperti pada contoh pada API klasik.
Inisialisasi toko
Perubahan signifikan menunggu kami di sini. Untuk menjelaskan bagaimana inisialisasi toko akan terjadi di versi ke-5, mari kita lihat bagaimana itu terjadi di versi ke-4. Saat kami membuat toko lewat
createStore
, kami langsung menginisialisasi, sehingga kami dapat menggunakannya di dalam
app.use
atau secara langsung.
import { createApp } from 'vue'
import App from './App.vue'
import store from './store'
const app = createApp(App)
app.use(store)
app.mount('#app')
// `this.$store`
// `useStore()` Composition API
import store from './store'
store.state.count // -> 0
store.commit('increment')
store.dispatch('increment')
store.getters.double // -> 4
Pada versi ke-5, kami mengakses setiap instance Vuex secara terpisah, yang menjamin independensi. Oleh karena itu, proses ini terlihat berbeda:
import { createApp } from 'vue'
import { createVuex } from 'vuex'
import App from './App.vue'
const app = createApp(App)
const vuex = createVuex()
app.use(vuex)
app.mount('#app')
Semua komponen sekarang memiliki kemampuan untuk mengakses semua instance Vuex secara langsung, daripada mengakses ruang global. Lihat contoh:
import { defineComponent } from 'vue'
import store from './store'
export default defineComponent({
name: 'App',
computed: {
counter () {
return this.$vuex.store(store)
}
}
})
Panggilan tersebut
$vuex.store
membuat dan menginisialisasi penyimpanan (ingat tentang mengganti nama
createStore
). Sekarang, setiap kali Anda berkomunikasi dengan repositori ini
$vuex.store
, Anda akan dikembalikan ke instance yang sudah dibuat. Dalam contoh, ini
this.counter
yang bisa kita gunakan lebih lanjut dalam kode. Anda juga dapat menginisialisasi toko melalui
createVuex()
.
Dan tentu saja, opsi untuk API Komposisi, yang
$vuex.store
digunakan sebagai gantinya
useStore
.
import { defineComponent } from 'vue'
import { useStore } from 'vuex'
import store from './store'
export default defineComponent({
setup () {
const counter = useStore(store)
return { counter }
}
})
Pendekatan yang dijelaskan di atas (menginisialisasi penyimpanan melalui komponen) memiliki kelebihan dan kekurangan. Di satu sisi, ini adalah pemisahan kode dan kemampuan untuk menambahkannya hanya jika diperlukan. Di sisi lain, menambahkan ketergantungan (sekarang Anda perlu mengimpor penyimpanan setiap kali Anda berencana menggunakannya). Oleh karena itu, jika Anda ingin menggunakan DI, maka opsi menggunakan
provide
:
import { createApp } from 'vue'
import { createVuex } from 'vuex'
import App from './App.vue'
import store from './store'
const app = createApp(App)
const vuex = createVuex()
app.use(vuex)
app.provide('name', store)
app.mount('#app')
Dan kemudian membuang toko ke dalam komponen (ada keinginan untuk menggantinya
name
dengan konstanta dan sudah menggunakannya):
import { defineComponent } from 'vue'
export default defineComponent({
name: 'App',
inject: ['name']
})
// Composition API
import { defineComponent, inject } from 'vue'
export default defineComponent({
setup () {
const store = inject('name')
return { store }
}
})
Tidak banyak kegembiraan tentang solusi ini, tetapi terlihat lebih eksplisit dan fleksibel daripada pendekatan saat ini. Hal yang sama tidak dapat dikatakan tentang penggunaan lebih lanjut. Sekarang terlihat seperti ini:
store.state.count // State
store.getters.double // Getters
store.commit('increment') // Mutations
store.dispatch('increment') // Actions
Versi baru diharapkan:
store.count // State
store.double // Getters
store.increment() // Actions
Semua entitas (status, pengambil, dan tindakan) dapat diakses secara langsung, sehingga bekerja dengannya lebih mudah dan lebih logis. Pada saat yang sama itu dihapus kebutuhan
mapState
,
mapGetters
,
mapActions
dan
mapMutations
, serta menulis dihitung tambahan properti.
Berbagi
Hal terakhir yang perlu dipertimbangkan adalah berbagi. Kami ingat bahwa di Vuex 5 kami tidak lagi memiliki modul bernama dan setiap sisi terpisah dan independen. Ini memungkinkan untuk mengimpornya saat dibutuhkan dan menggunakan data sesuai kebutuhan, seperti komponen. Muncul pertanyaan logis, bagaimana cara menggunakan banyak penyimpanan secara bersamaan? Di versi 4 masih ada namespace global dan kita perlu menggunakan
rootGetters
dan
rootState
merujuk ke toko yang berbeda dalam lingkup ini (seperti di versi 3). Pendekatan di Vuex 5 berbeda:
// store/greeter.js
import { defineStore } from 'vuex'
export default defineStore({
name: 'greeter',
state () {
return { greeting: 'Hello' }
}
})
// store/counter.js
import { defineStore } from 'vuex'
import greeterStore from './greeter'
export default defineStore({
name: 'counter',
use () {
return { greeter: greeterStore }
},
state () {
return { count: 0 }
},
getters: {
greetingCount () {
return `${this.greeter.greeting} ${this.count}'
}
}
})
Kami mengimpor toko, lalu mendaftarkannya
use
dan mengaksesnya. Semuanya terlihat lebih mudah jika Anda menggunakan API Komposisi:
// store/counter.js
import { ref, computed } from 'vue'
import { defineStore } from 'vuex'
import greeterStore from './greeter'
export default defineStore('counter', ({use}) => {
const greeter = use(greeterStore)
const count = 0
const greetingCount = computed(() => {
return `${greeter.greeting} ${this.count}`
})
return { count, greetingCount }
})
Satu-satunya hal yang perlu disebutkan adalah bahwa ia
use
bekerja dengan cara yang persis sama
vuex.store
dan bertanggung jawab untuk inisialisasi toko yang benar.
Dukungan TypeScript
Dengan perubahan API dan lebih sedikit abstraksi, dukungan TypeScript di versi 4 akan jauh lebih baik, tetapi kami masih membutuhkan banyak pekerjaan manual. Rilis versi 5 akan memungkinkan untuk menambahkan jenis jika perlu, dan di mana kita menginginkannya.
Kesimpulan
Vuex 5 terlihat menjanjikan dan persis seperti yang diharapkan banyak orang (memperbaiki bug lama, menambahkan fleksibilitas). Daftar lengkap diskusi dan tampilan tim inti dapat ditemukan di repositori Vue RFC .