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的了解,不正确的地方,希望大家指正跟留言交流,如對大家有幫助,歡迎轉載跟點贊,謝謝!