談一談Vuex

Vuex是什麼

官方文檔說道:Vuex 是一個專爲 Vue.js 應用程序開發的狀態管理模式。它採用集中式存儲管理應用的全部組件的狀態,並以相應的規則保證狀態以一種可預測的方式發生變化javascript

什麼是狀態管理模式

  • state,驅動應用的數據源;
  • view,以聲明方式將 state 映射到視圖;
  • actions,響應在 view 上的用戶輸入致使的狀態變化。

1560047234674

當咱們的應用遇到多個組件共享狀態時,單向數據流的簡潔性很容易被破壞,這時候咱們就須要一個全局的狀態管理來讓咱們的代碼結構化html

1560048024157

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

console.log(store.state.count) // -> 1

因爲 store 中的狀態是響應式的,在組件中調用 store 中的狀態簡單到僅須要在計算屬性中返回便可。觸發變化也僅僅是在組件的 methods 中提交 mutation。vue

在Vue組件中獲取狀態

// 建立一個 Counter 組件
const Counter = {
  template: `<div>{{ count }}</div>`,
  computed: {
    count () {
      return store.state.count  //this.$store.state.count
    }
  }
}}

從 store 實例中讀取狀態最簡單的方法就是在計算屬性中返回某個狀態java

咱們仍可使用mapState函數幫咱們生成計算屬性 mapState 函數返回的是一個對象vuex

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
    }
  })
}

getter

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

Vue.use(Vuex)

let state = {
    count: 0
}

let getters = {
    total: state => {
        return '$' + state.count;
    }
}

let mutations = {
    increment(_state, n){
        _state.count += n || 1;
    },
    decrement(){
        state.count -= 1;
    }
}

const store = new Vuex.Store({
    state,
    getters,
    mutations
})

export default store

getter 經過屬性訪問

<h3>count-{{$store.getters.total}}</h3>

getter 經過方法訪問

若是上面的方法想改變貨幣符號,那就要經過傳參方式來解決異步

let getters = {
    total: (state) => (symbol) => {
        return (symbol || '$') + state.count;
    }
}
<h3>count-{{$store.getters.total('¥')}}</h3>

mapGetters 輔助函數

<template>
    <div>
        <h3>count-{{total('¥')}}</h3>
    </div>
</template>

<script>
    import common from '../../common/common.js'
    import {mapState, mapMutations, mapGetters} from 'vuex';
    export default {
        computed: {
            ...mapGetters([
                'total'
            ])
        }
    }
</script>

mapGetters 輔助函數之別名

<template>
    <div>
        <h3>count-{{amount('¥')}}</h3>
    </div>
</template>

<script>
    import common from '../../common/common.js'
    import {mapState, mapMutations, mapGetters} from 'vuex';
    export default {
        computed: {
            ...mapGetters({
                amount: 'total'
            })
        }
    }
</script>

Mutations

更改 Vuex 的 store 中的狀態的惟一方法是提交 mutation。Vuex 中的 mutation 很是相似於事件,每一個 mutation 的方法都會有一個 state 的參數在 commit 的時候當回調形參傳過來,該形參就是 store.stateide

let mutations = {
    increment(_state){
        _state.count += 1;
    },
}

Mutation 傳參數——提交載荷(Payload)

能夠向 store.commit 傳入額外的參數,即 mutation 的 載荷(payload):函數

let mutations = {
    increment(_state){
        _state.count += 1;
    },
}

this.$store.commit('increment', 10);

大多數狀況下要傳多個參數,可是 mutation 的方法最多隻有兩個參數,一個是 state,另外一個是 payload,因此參數能夠用對象的方式去傳。ui

Mutation 觸發之 mapMutations 篇

<input type="button" value="increment" @click="increment(10)"/>
<script type="text/javascript">
    import {mapMutations} from 'vuex';
    methods: mapMutations(['increment'])
</script>

Mutation 觸發之 mapMutations 別名篇

<input type="button" value="increment" @click="add(10)"/>
<script type="text/javascript">
    import {mapMutations} from 'vuex';
    methods: mapMutations({
        add: 'increment'
    })
</script>

Mutation 觸發之對象展開運算符篇

<input type="button" value="increment" @click="increment(10)"/>
<script type="text/javascript">
    import {mapMutations} from 'vuex';
    methods: {
        ...mapMutations(['increment']),
    }
</script>

Mutation 觸發之對象展開運算符別名篇

<input type="button" value="increment" @click="add(10)"/>
<script type="text/javascript">
    import {mapMutations} from 'vuex';
    methods: {
        ...mapMutations({
            add: 'increment'
        }),
    }
</script>

Action

先引用官方文檔的說法this

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

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

實現上是沒問題,action 調用 mutation,但關於異步要放到 action 的說法,我的觀點是沒有這個必要,在 mutation 的小結中有說到過,mutation 只作同步也不是制性的

在使用 Action 前先與 Mutation 作個小結

  • action 並非必須的,項目中徹底能夠不須要 action
  • 異步操做可放 mutation 和 action,只要開發時方便,都沒有影響
  • 關於官方說 action 異步,mutation 同步的說法只是爲了能用 devtools 追蹤狀態變化。
  • action 中的方法和 mutation 同樣,最多隻有兩個形參,第一個爲 context,能夠理解爲 store,第二個爲手動傳的參數
  • action 用 commit() 來觸發 mutation
  • view 層經過 store.dispath 來分發 action

簡單使用

在 action

store.js

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

Vue.use(Vuex)

let state = {
    count: 0
}

let getters = {
    total: (state) => (symbol) => {
        return (symbol || '$') + state.count;
    }
}

let mutations = {
    increment(_state, n){
        console.log(arguments)
        _state.count += n || 1;
    },
    decrement(){
        state.count -= 1;
    }
}

let actions = {
    increment(context, n){
        context.commit('increment', n)
    }
}

const store = new Vuex.Store({
    state,
    getters,
    mutations,
    actions
})

export default store

分發 action

<input type="button" value="increment" @click="$store.dispatch('increment', 5)"/>

mapActions

和 mutation 的使用方法基本同樣

methods: {
    ...mapActions(['increment']),
    ...mapActions({add: 'increment'})
}

Module

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 的狀態
相關文章
相關標籤/搜索