這一篇會針對namespaced寫個說明,會針對前一篇vuex的延伸
前言
之前有寫了關於vuex的應用,但是一旦應用越來越大的時候,就會很難管理和尋找程式碼,而且命名也會越來越冗長,這篇就來說明一下如果用namespaced的方式,來更好的把vuex結構化。
導覽
針對之前範例重構成一支
再之前的vuex應用裡面,我們把actions,mutatiolns,state,getters全部拆成各自一支js檔,但是當我們有很多namespaced的時候,就會有非常多支的js檔,每次要加個actions都要再多支檔案跳來跳去,我們就先把所有的檔案整合成一支吧,在這次的範例我會把vuex的結構整合成這樣子
因為我們會有一個根層的,所以我改成root.js,然後把之前的多支檔案全部整合進root.js裡面,整合完的原始碼如下
store/root.js
export const state = {
count: 1
}
export const actions = {
addCount({
commit
}) {
commit('addCount', 1) //呼叫mutations
}
}
export const mutations = {
addCount(state, num) {
state.count += num //改變成state.js定義的count數值去加1,num是在actions我們丟進去的1
}
}
export const getters = {
count: state => state.count //取得state裡面的內容
}
再來看一下index.js
store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
import {
actions,
state,
mutations,
getters
} from './root'
Vue.use(Vuex)
export default new Vuex.Store({
actions,
state,
mutations,
getters,
struct: true
})
新增namespaced
我已經新增了一個資料夾為namespaced,還有兩支新的檔案,現在我要先加上countForNamespaced的部份,裡面的程式碼大致是跟root.js一模一樣,那就可以在一個有多個addCount的action,但觸發的時候有各自的邏輯,畫面如下
接著就來看看store部份的程式碼吧
store/namspaced/countForNamespaced.js
const state = {
count: 1
}
const actions = {
addCount({
commit
}) {
commit('addCount', 2) //呼叫mutations
}
}
const mutations = {
addCount(state, num) {
state.count += num //改變成state.js定義的count數值去加1,num是在actions我們丟進去的1
}
}
const getters = {
count: state => state.count //取得state裡面的內容
}
export default {
state,
actions,
mutations,
getters,
namespaced: true
}
store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
import {
actions,
state,
mutations,
getters
} from './root'
import countForNamespaced from './namespaced/countForNamespaced'
Vue.use(Vuex)
export default new Vuex.Store({
actions,
state,
mutations,
getters,
modules:{
countForNamespaced
},
struct: true
})
再來看看組件的部份吧,相關說明我也寫在程式裡面
<template>
<div id='countForNamespaced'>
<label>this is root count:{{count}}</label>
<button @click="addCount">+1 for root</button>
<label>this is namespaced count:{{countForNamespaced}}</label>
<button @click="addCountForNamespaced">+2 for namespaced</button>
</div>
</template>
<script>
import {
mapActions,
mapGetters
} from 'vuex'
export default {
name: 'countForNamespaced',
methods: {
...mapActions([ //對應root.js的部份
'addCount'
]),
...mapActions('countForNamespaced', { //對應了namespaced的部份
'addCountForNamespaced': 'addCount' //自定義組件的method名稱:vuex對應的actions
})
},
computed: {
...mapGetters([
'count'
]),
...mapGetters('countForNamespaced', {
'countForNamespaced': 'count'
})
}
}
</script>
<style scoped>
</style>
在vuex如何使用ajax
因為vuex一直強調的要先觸發action然後再由action去觸發mutation,所以ajax這種非同步的部份,也得寫在action裡面,所以我一樣建立了另一個ajax.js來示例一下,首先說明一下vue並不強調你要用什麼xhr相關的,目前比較多人用在vue的有三種,一種是vue-resource是官方維護的,但是官方已經說明不再維護此套,那另一種是標準es的fetch.js,一種則是axios,而在此示例我用的是多數人最熟悉的jquery來實做ajax,廢話不多說直接看一下吧
store/ajax.js
import $ from 'jquery'
const state = {
data: {}
}
const actions = {
async get({
commit
}) {
let result = await $.getJSON('your api data')
commit('get', result)
}
}
const mutations = {
get(state, data) {
state.data = data
}
}
const getters = {
data: state => state.data //取得state裡面的內容
}
export default {
state,
actions,
mutations,
getters,
namespaced: true //多加了namespaced為true
}
當然我們多加了這個namespaced,就要再index.js多加入參考
store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
import {
actions,
state,
mutations,
getters
} from './root'
import countForNamespaced from './namespaced/countForNamespaced'
import ajaxExample from './namespaced/ajaxExample' //加入新的參考
Vue.use(Vuex)
export default new Vuex.Store({
actions,
state,
mutations,
getters,
modules: {
countForNamespaced,
ajaxExample //加入新的參考
},
struct: true
})
接著是vuex的部份
store/namespaced/ajaxExample.js
import $ from 'jquery'
const state = {
data: {}
}
const actions = {
async get({
commit
}) {
let result = await $.getJSON('your api data')
commit('get', result)
}
}
const mutations = {
get(state, data) {
state.data = data
}
}
const getters = {
data: state => state.data //取得state裡面的內容
}
export default {
state,
actions,
mutations,
getters,
namespaced: true //多加了namespaced為true
}
最後則是component的部份
component/AjaxExample.vue
<template>
<div id='ajaxExample'>
</div>
</template>
<script>
import {
mapGetters,
mapActions
} from 'vuex'
export default {
name: 'ajaxExample',
methods: {
...mapActions('ajaxExample', [
'get'
])
},
computed: {
...mapGetters('ajaxExample', [
'data'
])
},
async created() {
await this.$store.dispatch('ajaxExample/get') //因為要取得預設資料,所以先去呼叫一次action,可用this去呼叫store
console.log(this.data) //這邊是getters去取得的data
}
}
</script>
<style scoped>
</style>
vuex整合vue-router
在實務上我們可能會有一種需求,就是必須必要資料載入後,才能進到頁面,所以我們需要在進入router之前,就先去觸發action然後取得資料,這時候用this.$store會取不到,這時候我們就需要import store進來再調用,範例如下
<template>
<div id='ajaxExample'>
</div>
</template>
<script>
import {
mapGetters,
mapActions
} from 'vuex'
import store from '../store'
export default {
name: 'ajaxExample',
methods: {
...mapActions('ajaxExample', [
'get'
])
},
computed: {
...mapGetters('ajaxExample', [
'data'
])
},
// async created() {
// await this.$store.dispatch('ajaxExample/get') //因為要取得預設資料,所以先去呼叫一次action,可用this去呼叫store
// console.log(this.data) //這邊是getters去取得的data
// },
async beforeRouteEnter(to, from, next) {
await store.dispatch('ajaxExample/get') //因為要取得預設資料,所以先去呼叫一次action,這時用得是import進來的store
next() //繼續執行
}
}
</script>
<style scoped>
</style>
結論
其實是否真的要使用vuex真的要看專案大小,因為一定會帶來相對的複雜度,但如果整個前端多人協作和非常複雜的話,相信一定會帶來非常大的幫助,vue其實非常好入門,如果你曾經學過一些前端framework,一些入門的部份看一下官網就會了,但專案和成員一多,相對抽象難懂的東西就會浮現出來,這邊記錄一下,如果有任何問題,再請提出來或指教一下,最後附上範例的github下載位址,有興趣的人再參考看看。
https://github.com/kinanson/vuex-example