天天看點

新手Vuex入門之mutations第三篇

3.mutations

通過第一篇跟第二篇,我們知道了如何去定義和擷取store裡面的狀态資料,但是光會定義跟擷取肯定是不夠的,很多的場景需要對這些狀态進行操作跟修改,那麼具體如何操控呢?這就是本篇要講的重點。重點來啦

1.隻有mutation能修改跟設定state

更改 Vuex 的 store 中的狀态的唯一方法是送出 mutation。Vuex 中的 mutation 非常類似于事件:每個 mutation 都有一個字元串的 事件類型 (type) 和 一個 回調函數 (handler)。這個回調函數就是我們實際進行狀态更改的地方,并且它會接受 state 作為第一個參數:

const store = new Vuex.Store({
  state: {
    count: 1
  },
  mutations: {
    // 事件類型 type 為 increment
    increment (state) {
      // 變更狀态
      state.count++
    }
  }
})
           

注意,我們不能直接 store.mutations.increment() 來調用,Vuex 規定必須使用 store.commit 來觸發對應 type 的方法:

2.我們可以向事件類型(type)傳參,如下:

mutations: {
  increment (state, n) {
    state.count += n
  }
}

// 調用
store.commit('increment', 10)
           

官方文檔給這個參數取了一個高大上的名字,叫mutation的載荷(payload)在大多數情況下,載荷應該是一個對象,這樣可以包含多個字段并且記錄的mutation會更易讀:

mutations: {
  increment (state, payload) {
    state.count += payload.amount
  }
}
           

3.關于store.commit來觸發mutation對應type的方法有兩種,看下面示例

//把type跟載荷分開
store.commit('increment',{
    amount:8
})
//把整個對象都傳給mutation函數
store.commit({
    type:'increment',
    amount:8
})
           

當然使用哪個方式,完全屬于個人喜歡,沒什麼絕對限制,挑一種自己喜歡的就好

在元件中也可以這樣調用:

<template>
<!--需要注意的是,對象中的屬性一定要加引号-->
<!--調用type 觸發回調-->
<button @click = "$store.commit('increment',9)">+</button>
<button @click ="$store.commit({type:'increment','amount':9})">+</button>
</template>
           

或者在methods對象中調用,需要Vuex中的一些輔助函數,這裡先不講述了

4.Mutation需遵守Vue的響應規則

如果你在state對象定義的是一些基礎類型的狀态資料,修改起來倒是簡單,如果定義的是一個對象并且你想要對此對象做些修改,那就要注意了,因為這裡涉及到幾個需要注意的點。看下面的示例:

const store = new Vuex.Store({
    state:{
        car:{
            brand:'大衆',
            color:'white'
        }
    }
})
           

這個時候,我們想給car添加一個price屬性,怎麼辦呢?是的,直接在color下面添加也可以,這樣是最好的。如果我們需要動态添加呢?那就得遵循Vue的響應規則了,如下所示:

const store = new Vuex.Store({
    state:{
        car:{
            brand:'大衆',
            color:'white'
        }
    },
    mutation:{
        addPrice(state) {
            Vue.set(state.car, 'price', 180000)
            // 或者:
            // state.car = { ...state.car, price: 180000 }
        }
    }
})
           

以上就是給對象動态添加屬性的兩種方式,對于已添加的對象,想要修改其屬性,可以直接更改,比如文中的例子,我想要把剛給汽車添加價格屬性作下修改,那麼store.state.car.price = '150000’即可。

至于為什麼要這樣,之前我們了解過,因為store中的狀态是響應式的,當我們更改狀态資料的時候,監視狀态的Vue元件也會自動更新,是以 Vuex 中的 mutation 也需要與使用 Vue 一樣遵守這些規則。

5.使用常量替代mutations中的事件類型(type)

就是使用常量來替代 mutation 事件的名字。使用常量替代mutation事件類型在各種 Flux 實作中是很常見的模式。這樣可以使linter之類的工具發揮作用,同時把這些常量放在單獨的檔案中可以讓整個app包含的 mutation 一目了然:

// mutation-types.js
export const SOME_MUTATION = 'SOME_MUTATION'
           
// store.js
import Vuex from 'vuex'
import { SOME_MUTATION } from './mutation-types'

const store = new Vuex.Store({
  state: { ... },
  mutations: {
    // 使用 ES2015 風格的計算屬性命名功能來使用一個常量作為函數名
    [SOME_MUTATION] (state) {
      // mutate state
    }
  }
})
           

用不用常量取決于你——在需要多人協作的大型項目中,這會很有幫助。但如果你不喜歡,你完全可以不這樣做。

6.mutation必須是同步函數

一條重要的原則就是要記住mutation必須是同步函數。為什麼?請參考下面的例子:

const store = new Vuex.Store({
    state:{
        car:{
            brand:'大衆',
            color:'white'
        }
    },
    mutation:{
        setColor(state) {//異步修改汽車的顔色
           new Promise((resolve,reject) => {
               state.color = 'blue';
           })
        }
    }
})

           

如上所示,如果是異步改變汽車的顔色,我們就不知道什麼時候顔色會發生改變,是以也就無法追蹤了,因為當 mutation 觸發的時候,回調函數還沒有被調用,這與 Mutation 的設計初心相悖,是以在 Vuex 中,mutation 都是同步事務:

store.commit('increment')
// 任何由 "increment" 導緻的狀态變更都應該在此刻完成。
           

寫在最後的話:

Vuex提供了一些非常友善的輔助函數,比如mapState、mapGetters、mapMutations、mapActions,這些部落客會專門整理一篇生意來主講這些,因為它們都是為了解決同一個問題而存在的。

本文僅此個人對Vuex的了解,不正确的地方,希望大家指正跟留言交流,如對大家有幫助,歡迎轉載跟點贊,謝謝!