Büyük Projelerde Vuex Nasıl Kurgulanmalıdır ?
Vuex eğitimlerine baktığınızda, çoğunun oldukça basit bir yapıda olduğunu görebilirsiniz. Mantık iyi açıklanmış, ancak ölçeklenebilirlik açısından yetersizdir.
İşte Vuex resmi dokümantasyonundan basit bir store örneği:
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment (state) {
state.count++
}
}
})
Bunu açıklamaya gerek yok. Bu makaleden önce zaten biraz Vue ve Vuex bilgisine sahip olduğunuzu varsayıyorum. Amacım bir store, mutation veya state ne olduğunu açıklamak değil.
Bunun yerine size 1000'den fazla state özelliği, mutations, actions ve getters içeren devasa bir store göstermek istiyorum.
Size en iyi sürdürülebilirlik, okunabilirlik ve yeniden kullanılabilirlik için store nasıl yapılandıracağınızı öğretmek istiyorum.
100.000'den fazla özelliğe sahip olsa da daha anlaşılır bir yapıda olur.
Hadi dalalım.
Modül Yapısı
Daha önce de söylediğimiz gibi, her şeyi tek bir dosyada tutmak bir karmaşa yaratacaktır. 50.000+ LOC dosyası istemezsiniz. Bu durum uygulamanızı tek bir component da tutmakla aynıdır.
Vuex, mağazayı modüllere bölerek burada bize yardımcı oluyor.
Bu örnek için iki modüllü bir store oluşturacağım. İşlemin 100'den fazla modül ve ayrıca her modüldeki 100'den fazla actions, getters ve mutations için aynı olduğunu unutmayın.
const userModule = {
namespaced: true,
state: () => ({}),
mutations: {},
actions: {},
getters: {}
}
const organisationModule = {
namespaced: true,
state: () => ({}),
mutations: {},
actions: {},
}
const store = new VueX.Store({
modules: {
user: userModule,
organisation: organisationModule
}
})
store.state.user // -> `userModule`'s state
store.state.organisation // -> `organisationModule`'s state
namespaced
özelliği burada inanılmaz derecede önemlidir. Onsuz, actions, mutations ve getters global namespace alanında hala kayıtlı olacaktır. namespaced
alanı özelliği true olarak ayarlandığında, actions, mutations ve getters da modüllere bölebiliriz.
Aynı ada sahip iki işleminiz varsa bunları global bir ad alanında bulundurmak, çakışmalara neden olur.
const userModule = {
namespaced: true,
state: () => ({}),
mutations: {},
actions: {
'SET_USER'() {},
'SET_USER_LOCATION'() {}
},
getters: {}
}
store.state.user['SET_USER']() // correct ✅
stote.state['SET_USER']() // wrong ❌
Gördüğünüz gibi, modül şu anda tamamen “local”. Buna yalnızca state üzerindeki user nesnesi aracılığıyla erişebiliriz.
Büyük uygulamamız için tam olarak istediğimiz şey bu.
Harika, şimdi modüllere ayrılmış bir store’umuz var!
Ancak, actions için kodlanmış string ifadeleri sevmiyorum. Kesinlikle sürdürülemez. Bu konuyu ele alalım.
Sizi Baş Ağrılarından Kurtaracak Yapı
Biz sadece her dosyadaki her modülden her özelliğe erişmek istemiyoruz. Bu cümle kulağa korkunç gibi geliyor.
Önce onları import etmek istiyoruz ardından bunu başarmak için mapGetter
, mapActions
veya mapMutations
kullanın.
// userModule.js
export const SET_USER = 'SET_USER'
export const SET_USER_LOCATION = 'SET_USER_LOCATION'
const userModule = {
namespaced: true,
state: () => ({}),
mutations: {},
actions: {
[SET_USER]() {},
[SET_USER_LOCATION]() {}
},
getters: {}
}
// vue file
import { mapActions } from 'vuex'
import { SET_USER, SET_USER_LOCATION } from './userModule.js'
...mapActions({
setUser: SET_USER,
setUserLocation: SET_USER_LOCATION
})
Bu size Vue dosyanız tarafından kullanılan store özniteliklerinin net bir görünümünü verir. Ama bu yeterli değil. Her şey hala tek bir dosyada. Doğru şekilde ölçeklendirmek için neler yapabileceğimize bir bakalım.
Dosya Yapısı
İdeal olarak, modülleri farklı klasörlere bölmek istiyoruz. Bu modüller içinde mutations, actions, getters, state niteliklerini ve türlerini farklı dosyalara bölmek istiyoruz.
Projemizin kök klasöründe store
klasörü oluşturulacaktır.
İki şey içerir:
index.js
filemodules
folder
index.js
dosyasını açıklamadan önce tek bir modülü nasıl böldüğümüze bir bakalım. user
modülünü kontrol edelim.
Tüm actions, mutations ve getters, types.js
dosyasında listelenmelidir. Yani, şöyle bir şey:
// actions
export const SET_USER = 'SET_USER'
export const SET_USER_LOCATION = 'SET_USER_LOCATION'
// mutations
// getters
Her kullanmak istediğimizde bu constları import ederek net bir görüşe sahip olacağız.
Şimdi actionlara bakalım. Bunları actions.js
dosyasına taşımak istiyoruz.
Bunu yapmak için, türleri import ederken yalnızca modül içindeki actions nesnesini kopyalamamız ve export default olarak aktarmamız gerekir:
import { SET_USER, SET_USER_LOCATION } from './types.js'
export default {
[SET_USER]() {},
[SET_USER_LOCATION]() {}
}
Aynı şeyi mutations ve getters için de yapacağız. State öznitelikleri index.js içinde kalacaktır (kullanıcı modülü klasörü içinde):
import actions from './actions.js'
import mutations from './mutations.js'
import getters from './getters.js'
const state = {}
export default {
namespaced: true,
state,
actions,
mutations,
getters
}
Artık tüm modüllerimiz birden fazla dosyaya bölünmüş durumda.
Geriye kalan tek şey, store klasöründeki index.js dosyasındaki tüm bu modülleri birbirine bağlamaktır:
import Vue from 'vue'
import Vuex from 'vuex'
// Modules import
import UserModule from 'modules/user'
import OrganisationModule from 'modules/organisation'
Vue.use(Vuex)
const state = {}
const actions = ({})
const mutations = ({})
const getters = ({})
const modules = {
user: userModule,
organisation: organisationModule
}
export default new Vuex.Store({
state,
actions,
mutations,
getters,
modules
})
Sonuç
Bu mimariyi kullanarak, devasa uygulamalarımızda ölçeklenebilirlikle ilgili sıfır sorun yaşadık.
Her şeyi bulmak çok kolay.
Tüm eylemlerin tam olarak nerede tetiklendiğini biliyoruz.
Sistem son derece sürdürülebilir.
İyileştirmeler için herhangi bir öneriniz varsa, lütfen bana bildirin. Fikrinizi duymayı çok isterim.