[vue]vuex和namespaced的應用

這一篇會針對namespaced寫個說明,會針對前一篇vuex的延伸

前言

之前有寫了關於vuex的應用,但是一旦應用越來越大的時候,就會很難管理和尋找程式碼,而且命名也會越來越冗長,這篇就來說明一下如果用namespaced的方式,來更好的把vuex結構化。

導覽

  1. 針對之前範例重構成一支
  2. 新增namespaced
  3. 在vuex如何使用ajax
  4. vuex整合vue-router
  5. 結論
 

針對之前範例重構成一支

再之前的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