Vuex的初探與實戰

1.背景 

  最近在作一個單頁面的管理後臺項目,爲了提升開發效率,使用了Vue框架來開發。爲了使各個部分的功能,獨立結構更加清晰,因而就拆分了不少組件,可是組件與組件之間數據共享成了一個問題,父子組件實現起來相對簡單,prop,$emit,$on就能搞定。除此以外,有不少兄弟組件和跨多級組件,實現起來過程繁瑣,在多人協同開發上,不利於統一管理,因而,開始了Vue的生態之一的Vux實踐之旅。vue

2.概述

每個 Vuex 應用的核心就是 store(倉庫)。「store」基本上就是一個容器,它包含着你的應用中大部分的狀態 (state)。ajax

Vuex 和單純的全局對象有如下兩點不一樣:vuex

1.Vuex 的狀態存儲是響應式的。當 Vue 組件從 store 中讀取狀態的時候,若 store 中的狀態發生變化,那麼相應的組件也會相應地獲得高效更新;2.你不能直接改變 store 中的狀態。改變 store 中的狀態的惟一途徑就是顯式地提交 (commit) mutation。這樣使得咱們能夠方便地跟蹤每個狀態的變化,從而讓咱們可以實現一些工具幫助咱們更好地瞭解咱們的應用npm

3.安裝使用

3.1.使用Vue-cli開發安裝vue包數組

cnpm install vuex --save

3.2.在src目錄下建立store文件夾並建立index.js以下(src/store/index.js)app

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex);

export default new Vuex.Store({
  state: {

  },
  getters: {

  },
  mutations: {

  },
  actions: {

  }
});

 而後在src文件下的main.js中使用框架

import Vue from 'vue'
import App from './App'
import store from './store'
Vue.config.productionTip = false

new Vue({ el: '#app', store, components: { App }, template: '<App/>' })

4.用法簡介

4.1.state異步

state是保存共享數據的,如今改store/index.js以下:函數

**
state: {
    count:0
  },
**

在components目錄下建立Index.vue如:工具

<template>
  <div class="index">
    {{count}}
  </div>
</template>

<script>
  export default {
    name: "index",
    computed:{
      count(){
        return this.$store.state.count;
      }
    }
  }
</script>

 結果以下:

咱們能夠經過組件的計算屬性來保存state裏面的值,那麼問題來了,若是store太多的話,咱們組件裏面的計算屬性豈不是成了這個樣子:

**
computed:{
  count(){
     return this.$store.state.count;
  },
   stateA(){
      return this.$store.state.stateA;
   },
   stateB(){
      return this.$store.state.stateB;
   }
}
**

這樣獲取共享狀態的數據也沒有什麼問題不過看起來仍是有大量的重複冗餘代碼,咱們可使用 mapState 輔助函數幫助咱們生成計算屬性,讓你少按幾回鍵:

當映射的計算屬性的名稱與 state 的子節點名稱相同時,咱們也能夠給 mapState 傳一個字符串數組。

**
import {mapState} from 'vuex'
  export default {
    name: "index",
    computed:{
      ...mapState(['count']),
    }
  }
**

 小結:使用 Vuex 並不意味着你須要將全部的狀態放入 Vuex。雖然將全部的狀態放到 Vuex 會使狀態變化更顯式和易調試,但也會使代碼變得冗長和不直觀。若是有些狀態嚴格屬於單個組件,最好仍是做爲組件的局部狀態。

 4.2.getter

有的時候咱們須要對共享狀態裏面的某一個屬性作一些處理後再使用,咱們能夠把數據獲取後再在組件的計算屬性中處理,舉個例子以下:

// store/index.js
state: {
    count:0,
    numbers:[0,1,2,3,4,5,6,7,8]
  },
// Index組件
<template>
  <div class="index">
    {{count}}
    <br>
    {{numbers.join()}}
  </div>
</template>
<script>
  import {mapState} from 'vuex'
  export default {
    name: "index",
    computed:{
      ...mapState(['count']),
      numbers(){
        return this.$store.state.numbers.filter((item)=>{
          return item>3;
        })
      }
    }
  }
</script>

結果以下:

 那麼問題來了,若是多個組件都要作一樣的處理,咱們就須要把一份代碼複製到多個地方,顯然是不大合理的,因而有了getter,能夠理解爲組件裏面的計算屬性。示例以下:

/ store/index.js
getters: {
    filterNumbers(state){
      return state.numbers.filter((item)=>{
        return item>3;
      })
    }
  },
// Index組件
<template>
  <div class="index">
    {{count}}
    <br>
    {{filterNumbers.join()}}
  </div>
</template>

<script>
  import {mapState} from 'vuex'
  export default {
    name: "index",
    computed:{
      ...mapState(['count']),
      filterNumbers(){
        return this.$store.getters.filterNumbers;
      }
    }
  }
</script>

結果徹底同樣,咱們能夠根據this.$store.getters.屬性名來獲取getters,也能夠經過mapGetters 輔助函數將 store 中的 getter 映射到局部計算屬性: 

具體實現方式以下:

<template>
  <div class="index">
    {{count}}
    <br>
    {{filterNumbers.join()}}
    <br>
    {{antherNumbers.join()}}
  </div>
</template>

<script>
  import {mapState,mapGetters} from 'vuex'
  export default {
    name: "index",
    computed:{
      ...mapState(['count']),6
      ...mapGetters(['filterNumbers']),
      ...mapGetters({
        antherNumbers:'filterNumbers'
      })
    }
  }
</script>

 若是用同一名字直接把數組做爲參數,若是想改一個名字,能夠傳入一個對象做爲參數,結果以下:

 4.3.mutation

在組件內,來自store的數據只能讀取,不能手動改變,改變store中數據惟一的途徑就是顯示的提交mutations。Vuex 中的 mutation 很是相似於事件:每一個 mutation 都有一個字符串的 事件類型 (type) 和 一個 回調函數 (handler)。這個回調函數就是咱們實際進行狀態更改的地方,而且它會接受 state 做爲第一個參數。改變代碼以下:

// store/index.js
mutations: {
add(state){
state.count++;
}
},

// Index組件
**
    <button @click="add">+</button>
**
    methods:{
      add(){
        this.$store.commit('add');
        console.log(this.count);
      }
**

連續點擊5次增長按鈕,發現count的值也改變了。固然,咱們也能夠傳參進去

// store/index.js
mutations: {
  add(state,n){
    state.count+=n;
  }
},

// Index組件
**
    <button @click="add">+</button>
**
    methods:{
      add(){
        this.$store.commit('add'10);
        console.log(this.count);
      }
**

觸發方法語句爲:this.$store.commit(方法名);也可使用輔助函數mapMutations代替:

**
methods:{
   ...mapMutations(['add']),
}
**

4.4.action

前面咱們講過,mutation有必須同步執行這個限制,咱們在業務需求中有時候須要在獲取ajax請求數據以後再操做或定時器操做數據,這些都屬於異步請求,要用actions來實現。具體實現以下:

// store/index.js
**
mutations: {
    changeCount(state){
      state.count=3000;
    },
  },
  actions: {
    changeCount3000s(context){
      setTimeout(()=>{
        context.commit('changeCount')
      },3000)

// Index組件
**
<button @click="changeCount3000s">點擊按鈕3s後count的值改變</button>
**
methods:{
  ...mapMutations(['add']),
    changeCount3000s(){
       this.$store.dispatch('changeCount3000s');
    }
  }
**

咱們在點擊按鈕3s後count的值改變爲3000,咱們能夠經過this.$store.dispatch(方法名)來觸發事件,也能夠經過輔助函數mapActions來觸發。

**
import {mapState,mapGetters,mapMutations,mapActions} from 'vuex'
 **
    methods:{
      ...mapMutations(['add']),
      ...mapActions(['changeCount3000s'])
    }
**

 

  學會以上幾個屬性的使用基本就能夠知足平時業務中的需求了,但使用Vuex會有必定的門檻和複雜性,它的主要使用場景是大型單頁面應用,若是你的項目不是很複雜,用一個bus也能夠實現數據的共享,可是它在數據管理,維護,還只是一個簡單的組件,而Vuex能夠更優雅高效地完成狀態管理,因此,是否使用Vuex取決於你的團隊和技術儲備。


參考資料:

《Vue.js實踐》  Vuex

相關文章
相關標籤/搜索