VueX'e Neler Geliyor?
Yayınlanan: 2022-03-10Vuex, Vue uygulamalarında durum yönetimi için çözümdür. Bir sonraki sürüm - Vuex 4 - resmi olarak yayınlanmadan önce son adımlardan geçiyor. Bu sürüm, Vue 3 ile tam uyumluluk getirecek, ancak yeni özellikler eklemiyor. Vuex her zaman güçlü bir çözüm ve birçok geliştiricinin Vue'daki durum yönetimi için ilk tercihi olmasına rağmen, bazı geliştiriciler daha fazla iş akışı sorununun ele alınmasını ummuştu. Ancak, Vuex 4 kapıdan yeni çıkarken bile, Kia King Ishii (Vue çekirdek ekip üyesi) Vuex 5 için planlarından bahsediyor ve gördüklerim beni o kadar heyecanlandırdı ki sizinle paylaşmak zorunda kaldım. tüm. Vuex 5 planlarının kesinleşmediğini unutmayın, bu nedenle Vuex 5 piyasaya sürülmeden önce bazı şeyler değişebilir, ancak büyük ölçüde bu makalede gördüğünüze benzer bir şekilde sonuçlanırsa, geliştirici deneyiminde büyük bir gelişme olacaktır.
Vue 3'ün ortaya çıkışı ve onun kompozisyon API'si ile insanlar el yapımı basit alternatifler arıyorlar. Örneğin, Vuex'e İhtiyacınız Olmayabilir , paylaşılan durum depoları oluşturmak için provide/inject
etme ile birlikte kompozisyon API'sini kullanmak için nispeten basit, ancak esnek ve sağlam bir model gösterir. Gabor'un makalesinde belirttiği gibi, bu (ve diğer alternatifler) yalnızca daha küçük uygulamalarda kullanılmalıdır çünkü bunlar doğrudan kodla ilgili olmayan şeylerden yoksundur: topluluk desteği, belgeler, sözleşmeler, iyi Nuxt entegrasyonları ve geliştirici araçlar.
Bu sonuncusu benim için her zaman en büyük sorunlardan biri olmuştur. Vue devtools tarayıcı uzantısı, Vue uygulamalarında hata ayıklamak ve geliştirmek için her zaman harika bir araç olmuştur ve Vuex denetçisini "zaman yolculuğu" ile kaybetmek, önemsiz olmayan uygulamalarda hata ayıklamak için oldukça büyük bir kayıp olacaktır.

Neyse ki Vuex 5 ile pastamızı yiyip yiyebileceğiz. Daha çok bu kompozisyon API alternatifleri gibi çalışacak, ancak resmi bir devlet yönetim kütüphanesi kullanmanın tüm faydalarını koruyacak. Şimdi nelerin değişeceğine bir göz atalım.
Mağaza Tanımlama
Bir Vuex mağazasıyla herhangi bir şey yapmadan önce bir tane tanımlamamız gerekiyor. Vuex 4'te bir mağaza tanımı şöyle görünecektir:
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') } } })
Her mağazanın dört bölümü vardır: state
verileri depolar, getters
size hesaplanan durumu verir, durumu değiştirmek için mutations
kullanılır ve actions
, mağazayla ilgili herhangi bir şeyi gerçekleştirmek için mağazanın dışından çağrılan yöntemlerdir. Genellikle, bu örnekte gösterildiği gibi eylemler yalnızca bir mutasyon gerçekleştirmez. Bunun yerine, asenkron görevleri yapmak için kullanılırlar çünkü mutasyonlar senkronize olmalıdır veya sadece daha karmaşık veya çok adımlı işlevsellik uygularlar. Eylemler de durumu kendi başlarına değiştiremezler; bir mutator kullanmaları gerekir. Peki Vuex 5 neye benziyor?
import { defineStore } from 'vuex' export const counterStore = defineStore({ name: 'counter', state() { return { count: 0 } }, getters: { double () { return this.count * 2 } }, actions: { increment () { this.count++ } } })
Burada dikkat edilmesi gereken birkaç değişiklik var. İlk olarak createStore yerine createStore
defineStore
. Bu fark önemsizdir, ancak daha sonra ele alacağımız anlamsal nedenlerle oradadır. Ardından, mağaza için daha önce ihtiyaç duymadığımız bir name
sağlamamız gerekiyor. Geçmişte, modüller kendi adlarına sahipti, ancak modülün kendisi tarafından sağlanmadılar; bunlar yalnızca, onları ekleyen ana mağaza tarafından atandıkları mülk adıydı. Şimdi, modül yok . Bunun yerine her modül ayrı bir mağaza olacak ve bir adı olacak. Bu ad, daha sonra bahsedeceğimiz Vuex kayıt defteri tarafından kullanılır.
Bundan sonra, durumu sadece başlangıç durumuna ayarlamak yerine ilk state
döndüren bir fonksiyon yapmamız gerekiyor. Bu, bileşenlerdeki data
seçeneğine benzer. Vuex 4'te yaptığımıza çok benzer getters
yazıyoruz, ancak durumu her alıcı için bir parametre olarak kullanmak yerine, state
ulaşmak için this
kullanabilirsiniz. Aynı şekilde, actions
içeri aktarılan bir context
nesnesi hakkında endişelenmesine gerek yoktur: this
sadece her şeye erişmek için kullanabilirler. Son olarak, mutations
yoktur. Bunun yerine, mutasyonlar actions
birleştirilir. Kia, mutasyonların çok sık basit belirleyiciler haline geldiğini ve onları anlamsız bir şekilde ayrıntılı hale getirdiğini ve bu yüzden onları kaldırdıklarını kaydetti. Durumu doğrudan mağazanın dışından mutasyona uğratmanın "tamam" olup olmadığından bahsetmedi, ancak durumu doğrudan bir eylemden değiştirmemize kesinlikle izin verildi ve teşvik edildi ve Flux modeli, durumun doğrudan mutasyonuna kaşlarını çattı.
Not : Bileşen oluşturmak için seçenekler API'si yerine kompozisyon API'sini tercih edenler için, kompozisyon API'sini kullanmaya benzer şekilde mağazalar oluşturmanın da bir yolu olduğunu öğrenmekten memnun olacaksınız.
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 } })
Yukarıda gösterildiği gibi, ad, defineStore
için ilk argüman olarak iletilir. Gerisi, bileşenler için bir kompozisyon işlevi gibi görünüyor. Bu, seçenekler API'sini kullanan önceki örnekle tamamen aynı sonucu verecektir.
Mağazanın Örneklendirilmesini Sağlamak
Vuex 4'te işler Vuex 3'e göre değişti, ancak işlerin kontrolden çıkmasını önlemek için sadece v4'e bakacağım. createStore
, onu zaten başlattınız. Ardından, uygulamanızda ya app.use
aracılığıyla ya da doğrudan kullanabilirsiniz:
import { createApp } from 'vue' import App from './App.vue' // Your root component import store from './store' // The store definition from earlier const app = createApp(App) app.use(store) app.mount('#app') // Now all your components can access it via `this.$store` // Or you can use in composition components with `useStore()` // ----------------------------------------------- // Or use directly... this is generally discouraged import store from './store' store.state.count // -> 0 store.commit('increment') store.dispatch('increment') store.getters.double // -> 4
Bu, Vuex 5'in v4'ten biraz daha karmaşık hale getirdiği bir şeydir. Artık her uygulama ayrı bir Vuex örneği alabilir, bu da her uygulamanın aralarında veri paylaşmadan aynı mağazaların ayrı örneklerine sahip olmasını sağlar. Uygulamalar arasında mağaza örnekleri paylaşmak istiyorsanız, bir Vuex örneğini paylaşabilirsiniz.

import { createApp } from 'vue' import { createVuex } from 'vuex' import App from './App.vue' // Your root component const app = createApp(App) const vuex = createVuex() // create instance of Vuex app.use(vuex) // use the instance app.mount('#app')
Artık tüm bileşenlerinizin Vuex örneğine erişimi var. Mağaza(lar)ınızın tanımını doğrudan vermek yerine, onları kullanmak istediğiniz bileşenlere aktarın ve bunları somutlaştırmak ve kaydetmek için Vuex örneğini kullanın:
import { defineComponent } from 'vue' import store from './store' export default defineComponent({ name: 'App', computed: { counter () { return this.$vuex.store(store) } } })
$vuex.store
çağrılması, mağazayı Vuex örneğinde başlatır ve kaydeder. O andan itibaren, o mağazada $vuex.store
her kullandığınızda, tekrar somutlaştırmak yerine önceden somutlaştırılmış mağazayı size geri verecektir. store
yöntemini doğrudan createVuex()
tarafından oluşturulan bir Vuex örneğinde çağırabilirsiniz.
Artık mağazanıza this.counter
aracılığıyla bu bileşenden erişilebilir. Bileşeniniz için kompozisyon API'sini kullanıyorsanız, this.$vuex.store
useStore
useStore kullanabilirsiniz:
import { defineComponent } from 'vue' import { useStore } from 'vuex' // import useStore import store from './store' export default defineComponent({ setup () { const counter = useStore(store) return { counter } } })
Mağazayı doğrudan bileşene içe aktarmanın ve onu orada somutlaştırmanın artıları ve eksileri vardır. Kod bölmenize ve mağazayı yalnızca gerektiği yerde tembelce yüklemenize olanak tanır, ancak şimdi bir ebeveyn tarafından enjekte edilmek yerine doğrudan bir bağımlılıktır (her kullanmak istediğinizde içe aktarmanız gerektiğinden bahsetmiyoruz). Uygulamanın tamamında bunu sağlamak için bağımlılık enjeksiyonunu kullanmak istiyorsanız, özellikle de kod bölmenin yardımcı olmayacağı uygulamanın kökünde kullanılacağını biliyorsanız provide
şunları kullanabilirsiniz:
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('store', store) // provide the store to all components app.mount('#app')
Ve onu kullanacağınız herhangi bir bileşene enjekte edebilirsiniz:
import { defineComponent } from 'vue' export default defineComponent({ name: 'App', inject: ['store'] }) // Or with Composition API import { defineComponent, inject } from 'vue' export default defineComponent({ setup () { const store = inject('store') return { store } } })
Bu ekstra ayrıntı konusunda heyecanlı değilim, ancak daha açık ve daha esnek, benim de hayranım. Bu tür kodlar genellikle projenin başında hemen bir kez yazılır ve daha sonra sizi bir daha rahatsız etmez, ancak şimdi her yeni mağazayı sağlamanız veya her kullanmak istediğinizde içe aktarmanız gerekir, ancak kod modüllerini içe aktarmak veya enjekte etmek, genellikle başka herhangi bir şeyle çalışmak zorunda olduğumuz şeydir, bu yüzden sadece Vuex'in insanların zaten nasıl çalışma eğiliminde olduğu konusunda daha fazla çalışmasını sağlıyor.
Mağaza Kullanmak
Esnekliğin ve mağazaların kompozisyon API'sini kullanan bir bileşenle aynı şekilde tanımlanmasının yeni yolunun hayranı olmanın yanı sıra, beni her şeyden daha çok heyecanlandıran bir şey daha var: mağazaların nasıl kullanıldığı. Vuex 4'te bir mağaza kullanmanın nasıl göründüğü aşağıda açıklanmıştır.
store.state.count // Access State store.getters.double // Access Getters store.commit('increment') // Mutate State store.dispatch('increment') // Run Actions
State
, getters
, mutations
ve actions
tümü, farklı özellikler veya yöntemlerle farklı şekillerde işlenir. Bu, daha önce övdüğüm açık olma avantajına sahiptir, ancak bu açıklık bize gerçekten hiçbir şey kazandırmaz. Ve bu API'nin kullanımı yalnızca ad alanlı modüller kullandığınızda daha da zorlaşır. Karşılaştırıldığında, Vuex 5 tam olarak normalde umduğunuz gibi çalışıyor:
store.count // Access State store.double // Access Getters (transparent) store.increment() // Run actions // No Mutators
Her şey - durum, alıcılar ve eylemler - doğrudan mağazanın kökünde bulunur, bu da çok daha az ayrıntıyla kullanımı kolaylaştırır ve seçenekler API'si veya yazma için mapState
, mapGetters
, mapActions
ve mapMutations
kullanma ihtiyacını pratik olarak ortadan kaldırır. kompozisyon API'si için ekstra computed
ifadeler veya basit işlevler. Bu, bir Vuex mağazasının tıpkı kendi oluşturacağınız normal bir mağaza gibi görünmesini ve hareket etmesini sağlar, ancak eklentilerin, hata ayıklama araçlarının, resmi belgelerin vb. tüm avantajlarını alır.
Beste Mağazaları
Vuex 5'in bugün bakacağımız son yönü, birleştirilebilirliktir. Vuex 5, tümüne tek mağazadan erişilebilen ad alanlı modüllere sahip değildir. Bu modüllerin her biri tamamen ayrı bir mağazaya bölünecektir. Bileşenler için bu kadar basit: sadece ihtiyaç duydukları mağazaları ithal ederler ve onları çalıştırıp kullanırlar. Peki ya bir mağaza başka bir mağazayla etkileşim kurmak isterse? v4'te ad alanı her şeyi sarar, bu nedenle commit
ve dispatch
çağrılarınızda ad alanını kullanmanız, rootGetters
ve rootState
kullanmanız ve ardından alıcılara ve durumdan erişmek istediğiniz ad alanlarına doğru ilerlemeniz gerekir. Vuex 5'te şu şekilde çalışır:
// 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' // Import the store you want to interact with export default defineStore({ name: 'counter', // Then `use` the store use () { return { greeter: greeterStore } }, state () { return { count: 0 } }, getters: { greetingCount () { return `${this.greeter.greeting} ${this.count}' // access it from this.greeter } } })
v5 ile, kullanmak istediğimiz mağazayı içe aktarıyoruz, ardından use
ile kaydettiriyoruz ve şimdi mağazanın her yerinden, verdiğiniz mülk adı ne olursa olsun erişilebilir. Mağaza tanımının kompozisyon API varyasyonunu kullanıyorsanız işler daha da basittir:
// store/counter.js import { ref, computed } from 'vue' import { defineStore } from 'vuex' import greeterStore from './greeter' // Import the store you want to interact with export default defineStore('counter', ({use}) => { // `use` is passed in to function const greeter = use(greeterStore) // use `use` and now you have full access const count = 0 const greetingCount = computed(() => { return `${greeter.greeting} ${this.count}` // access it like any other variable }) return { count, greetingCount } })
Artık ad alanlı modül yok. Her mağaza ayrıdır ve ayrı kullanılmaktadır. Bir mağazayı başka bir mağazanın içinde kullanılabilir hale getirmek için use
. Her iki örnekte de use
, temelde daha önceki vuex.store
ile aynı mekanizmadır ve mağazaların doğru Vuex örneğiyle somutlaştırılmasını sağlarlar.
TypeScript Desteği
TypeScript kullanıcıları için Vuex 5'in en büyük yönlerinden biri, basitleştirmenin her şeye tip eklemeyi kolaylaştırmasıdır. Vuex'in eski sürümlerinin neredeyse imkansız hale getirdiği soyutlama katmanları ve şu anda Vuex 4 ile türleri kullanma yeteneğimizi artırdılar, ancak yeterli miktarda tür desteği almak için hala çok fazla manuel çalışma var, oysa v5'te , türlerinizi umduğunuz ve beklediğiniz gibi satır içine koyabilirsiniz.
Çözüm
Vuex 5 neredeyse tam olarak benim - ve muhtemelen diğer pek çok kişinin - olmasını umduğum gibi görünüyor ve yakında gelemeyeceğini hissediyorum. Vuex'in çoğunu basitleştirir, ilgili zihinsel yükün bir kısmını ortadan kaldırır ve yalnızca esneklik eklediğinde daha karmaşık veya ayrıntılı hale gelir. Bu değişiklikler hakkında ne düşündüğünüzü ve bunun yerine veya ek olarak hangi değişiklikleri yapabileceğinizi aşağıya yorum olarak bırakın. Veya doğrudan kaynağa gidin ve çekirdek ekibin ne düşündüğünü görmek için listeye bir RFC (Yorum İsteği) ekleyin.