Vuex的五個核心屬性

Vuex的五個核心屬性vue

Vuex的五個核心概念

本文參考自Vue文檔,說的很是詳細,建議看文檔。vuex

Vuex是什麼?

VueX 是一個專門爲 Vue.js 應用設計的狀態管理架構,統一管理和維護各個vue組件的可變化狀態(你能夠理解成 vue 組件裏的某些 data )。數組

Vue有五個核心概念,stategettersmutationsactionsmodules。本文將對這個五個核心概念進行梳理。架構

總結

state => 基本數據 
getters => 從基本數據派生的數據 
mutations => 提交更改數據的方法,同步! 
actions => 像一個裝飾器,包裹mutations,使之能夠異步。 
modules => 模塊化Vuexapp

State

state即Vuex中的基本數據!異步

單一狀態樹

Vuex使用單一狀態樹,即用一個對象就包含了所有的狀態數據。state做爲構造器選項,定義了全部咱們須要的基本狀態參數。模塊化

在Vue組件中得到Vuex屬性

  • 咱們能夠經過Vue的Computed得到Vuex的state,以下:
const store = new Vuex.Store({
    state: {
        count:0
    }
})
const app = new Vue({
    //..
    store,
    computed: {
        count: function(){
            return this.$store.state.count
        }
    },
    //..
})

每當 store.state.count 變化的時候, 都會從新求取計算屬性,而且觸發更新相關聯的 DOM。函數

mapState輔助函數

當一個組件須要獲取多個狀態時候,將這些狀態都聲明爲計算屬性會有些重複和冗餘。爲了解決這個問題,咱們可使用 mapState 輔助函數幫助咱們生成計算屬性,讓你少按幾回鍵。工具

// 在單獨構建的版本中輔助函數爲 Vuex.mapState
import { mapState } from 'vuex'

export default {
  // ...
  computed: mapState({
    // 箭頭函數可以使代碼更簡練
    count: state => state.count,

    // 傳字符串參數 'count' 等同於 `state => state.count`
    countAlias: 'count',

    // 爲了可以使用 `this` 獲取局部狀態,必須使用常規函數
    countPlusLocalState (state) {
      return state.count + this.localCount
    }
  })
}

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

computed: mapState([
  // 映射 this.count 爲 store.state.count
  'count'
])

對象展開運算符

mapState 函數返回的是一個對象。咱們如何將它與局部計算屬性混合使用呢?一般,咱們須要使用一個工具函數將多個對象合併爲一個,以使咱們能夠將最終對象傳給 computed 屬性。可是自從有了對象展開運算符,咱們能夠極大地簡化寫法:

computed: {
  localComputed () //本地計算屬性
  //使用對象展開運算符將此對象混入到外部對象中
  ...mapState({
    //..
  })
}

對象運算符 

... 展開運算符(spread operator)容許一個表達式在某處展開。展開運算符在多個參數(用於函數調用)或多個元素(用於數組字面量)或者多個變量(用於解構賦值)的地方可使用。

展開運算符不能用在對象當中,由於目前展開運算符只能在可遍歷對象(iterables)可用。iterables的實現是依靠[Symbol.iterator]函數,而目前只有Array,Set,String內置[Symbol.iterator]方法,而Object還沒有內置該方法,所以沒法使用展開運算符。不過ES7草案當中已經加入了對象展開運算符特性。

    function test(a,b,c) {
        console.log(a);
        console.log(b);
        console.log(c);
    }
    var args = [0,1,2];
    test(...args);  // 0  1  2

ES7草案中的對象展開運算符 

ES6中還不支持對對象的展開運算符,可是ES7中將支持。對象展開運算符符可讓咱們更快捷地操做對象,以下例子:

    let {x,y,...z}={x:1,y:2,a:3,b:4};
    x; //1
    y; //2
    z; //{a:3,b:4}

組件仍然保有局部狀態

使用 Vuex 並不意味着你須要將全部的狀態放入 Vuex。雖然將全部的狀態放到 Vuex 會使狀態變化更顯式和易調試,但也會使代碼變得冗長和不直觀。

若是有些狀態嚴格屬於單個組件,最好仍是做爲組件的局部狀態。你應該根據你的應用開發須要進行權衡和肯定。

getters

即從store的state中派生出的狀態。

getters接收state做爲其第一個參數,接受其餘 getters 做爲第二個參數,如不須要,第二個參數能夠省略以下例子:

const store = new Vuex.Store({
    state: {
        count:0
    },
    getters: {
        // 單個參數
        countDouble: function(state){
            return state.count * 2
        },
        // 兩個參數
        countDoubleAndDouble: function(state, getters) {
            return getters.countDouble * 2
        }
    }
})

與state同樣,咱們也能夠經過Vue的Computed得到Vuex的getters。

const app = new Vue({
    //..
    store,
    computed: {
        count: function(){
            return this.$store.state.count
        },
        countDouble: function(){
            return this.$store.getters.countDouble
        },
        countDoubleAndDouble: function(){
            return this.$store.getters.countDoubleAndDouble
        }
    },
    //..
})

mapGetters 輔助函數

mapGetters 輔助函數僅僅是將 store 中的 getters 映射到局部計算屬性,與state相似

import { mapGetters } from 'vuex'

export default {
  // ...
  computed: {
  // 使用對象展開運算符將 getters 混入 computed 對象中
    ...mapGetters([
      'countDouble',
      'CountDoubleAndDouble',
      //..
    ])
  }
}

若是你想將一個 getter 屬性另取一個名字,使用對象形式:

mapGetters({
  // 映射 this.double 爲 store.getters.countDouble
  double: 'countDouble'
})

mutations

提交mutation是更改Vuex中的store中的狀態的惟一方法。

mutation必須是同步的,若是要異步須要使用action。

每一個 mutation 都有一個字符串的 事件類型 (type) 和 一個 回調函數 (handler)。這個回調函數就是咱們實際進行狀態更改的地方,而且它會接受 state 做爲第一個參數,提交載荷做爲第二個參數。(提交荷載在大多數狀況下應該是一個對象),提交荷載也能夠省略的。

const store = new Vuex.Store({
  state: {
    count: 1
  },
  mutations: {
    //無提交荷載
    increment(state) {
        state.count++
    }
    //提交荷載
    incrementN(state, obj) {
      state.count += obj.n
    }
  }
})

你不能直接調用一個 mutation handler。這個選項更像是事件註冊:「當觸發一個類型爲 increment 的 mutation 時,調用此函數。」要喚醒一個 mutation handler,你須要以相應的 type 調用 store.commit 方法:

//無提交荷載
store.commit('increment')
//提交荷載
store.commit('incrementN', {
    n: 100
    })

對象風格的提交方式

咱們也可使用這樣包含 type 屬性的對象的提交方式。

store.commit({
  type: 'incrementN',
  n: 10
})

Mutations 需遵照 Vue 的響應規則

    • 最好提早在你的 store 中初始化好全部所需屬性。
    • 當須要在對象上添加新屬性時,你應該 
      • 使用 Vue.set(obj, 'newProp', 123), 或者
      • 以新對象替換老對象。例如,利用對象展開運算符咱們能夠這樣寫state.obj = {...state.obj, newProp: 123 }

mapMutations 輔助函數

與其餘輔助函數相似,你能夠在組件中使用 this.$store.commit(‘xxx’) 提交 mutation,或者使用 mapMutations 輔助函數將組件中的 methods 映射爲 store.commit 調用(須要在根節點注入 store)。

import { mapMutations } from 'vuex'

export default {
  //..
  methods: {
    ...mapMutations([
      'increment' // 映射 this.increment() 爲 this.$store.commit('increment')
    ]),
    ...mapMutations({
      add: 'increment' // 映射 this.add() 爲 this.$store.commit('increment')
    })
  }
}

actions

Action 相似於 mutation,不一樣在於:

  • Action 提交的是 mutation,而不是直接變動狀態。
  • Action 能夠包含任意異步操做。

咱們用以下例子來結束actions:

const store = new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    increment (state) {
      state.count++
    }
  },
  actions: {
    increment (context) {
      setInterval(function(){
        context.commit('increment')
      }, 1000)
    }
  }
})

注意:Action 函數接受一個與 store 實例具備相同方法和屬性的 context 對象,所以你能夠調用 context.commit 提交一個 mutation,或者經過 context.state 和 context.getters 來獲取 state 和 getters。

分發actions

Action 經過 store.dispatch 方法觸發:

store.dispatch('increment')

其餘與mutations相似的地方

Actions 支持一樣的載荷方式和對象方式進行分發:

// 以載荷形式分發
store.dispatch('incrementN', {
  n: 10
})

// 以對象形式分發
store.dispatch({
  type: 'incrementN',
  n: 10
})

mapActions輔助函數

你在組件中使用 this.$store.dispatch('xxx') 分發 action,或者使用 mapActions 輔助函數將組件的 methods 映射爲 store.dispatch 調用(須要先在根節點注入 store):

import { mapActions } from 'vuex'

export default {
  //..
  methods: {
    ...mapActions([
      'incrementN' //映射 this.incrementN() 爲 this.$store.dispatch('incrementN')
    ]),
    ...mapActions({
      add: 'incrementN' //映射 this.add() 爲 this.$store.dispatch('incrementN')
    })
  }
}

Modules

使用單一狀態樹,致使應用的全部狀態集中到一個很大的對象。可是,當應用變得很大時,store 對象會變得臃腫不堪。

爲了解決以上問題,Vuex 容許咱們將 store 分割到模塊(module)。每一個模塊擁有本身的 state、mutation、action、getters、甚至是嵌套子模塊——從上至下進行相似的分割:

const moduleA = {
  state: { ... },
  mutations: { ... },
  actions: { ... },
  getters: { ... }
}

const moduleB = {
  state: { ... },
  mutations: { ... },
  actions: { ... }
}

const store = new Vuex.Store({
  modules: {
    a: moduleA,
    b: moduleB
  }
})

store.state.a // -> moduleA 的狀態
store.state.b // -> moduleB 的狀態

模塊的局部狀態

對於模塊內部的 mutation 和 getter,接收的第一個參數是模塊的局部狀態,對於模塊內部的 getter,根節點狀態會做爲第三個參數:

const moduleA = {
  state: { count: 0 },
  mutations: {
    increment (state) {
      // state 模塊的局部狀態
      state.count++
    }
  },

  getters: {
    doubleCount (state) {
      return state.count * 2
    },
    sumWithRootCount (state, getters, rootState) {
      return state.count + rootState.count
    }
  }
}

一樣,對於模塊內部的 action,context.state 是局部狀態,根節點的狀態是 context.rootState:

const moduleA = {
  // ...
  actions: {
    incrementIfOddOnRootSum (context) {
      if ((context.state.count + context.rootState.count) % 2 === 1) {
        commit('increment')
      }
    }
  }
}
相關文章
相關標籤/搜索