接續前面的內容,還有幾個東西沒有研究到...
前面是學到的向倉庫取資料的辦法,再來就是要學怎麼寫資料進去倉庫。唯一方法是提交(commit)某個mutations屬性,在裡面定義一個function和callback,其中有兩個參數,分別為state與payload(傳遞進來的值)。
state: {
product: 't-shirt',
price: 500,
quantity: 100
},
mutations: {
setQuantity(state, payload) {
state.quantity = payload
}
},
若今天要更新state.quantity時,可以在元件新增且綁定到按鈕點擊事件上。點擊按鈕,元件會提交(commit) setQuantity給mutations,再把this.qty傳出去。
<template>
<input type="text" v-model.number="qty" />
<button @click="unpdateQty">Click</button>
</template>
<script>
export default {
data() {
return {
qty: 0,
};
},
methods: {
updateQty() {
this.$store.commit("setQuantity", this.qty);
},
},
};
</script>
另外,想要傳物件的話,可以這樣寫
this.$store.commit({
type: 'setQuantity',
qty: this.qty
})
對應的mutations也要改
mutations: {
setQuantity(state, payload) {
state.quantity = payload.qty
}
},
和前兩個一樣。透過mapMutations將setQuantity引入元件,mapMutations回傳一個對應的setQuantity方法,並自動帶入payload功能。
<template>
<input type="text" v-model.number="qty" />
//此處有多帶參數
<button @click="setQuantity(qty)">Click</button>
</template>
<script>
import { mapMutations } from "vuex";
export default {
data() {
return {
qty: 0,
};
},
methods: {
...mapMutations(["setQuantity"]),
},
};
</script>
注意!! mapMutations中所有操作必須為同步,故無法在裡面使用async/await或promise等非同步操作。
作用類似mutations,但不能直接操控state的資料,也因此在這裡可以執行非同步的任務,再把結果傳回mutations去改資料。
接續範例,state.product變成空物件,在actions加上fetchProductInf函式
state: {
product: {}
},
actions: {
fetchProductInfo(context,payload){
//假設API回傳{"id":"123", "name": "t-shirt", "price": 500, "quantity": 100}
fetch('...')
.then(res=>res.json)
.then(data=>context.commit('setProductInfo',data))
}
},
actions中有兩個參數 :
export default {
created() {
this.$store.dispatch("setProductInfo", { id: "001" });
},
};
fetchProductInfo在created或mounted階段(也就是實體被建立)被dispatch,會透過API對後端發送邀請,並回傳API結果透過context.commit()提交給setProductInfo。
Actions也又自己的mapActions可以用,用下面的寫法也可以得到剛剛的結果。
import { mapActions } from "vuex";
export default {
methods: {
...mapActions(['fetchProductInfo'])
},
created() {
this.fetchProductInfo({ id: "001" });
},
};
在結構圖沒有卻在建立的src/store/index.js中出現的module。他的功能就是管理不斷擴大的state資料。
在modules裡面可以將store拆成兩塊,moduleA和moduleB。
const moduleA = {
state: () => ({ ... }),
mutations: { ... },
actions: { ... },
getters: { ... }
}
const moduleB = {
state: () => ({ ... }),
mutations: { ... },
actions: { ... }
}
export default createStore({
state:{ ... },
mutations: { ... },
actions: { ... },
getters: { ... },
modules: {
moduleA,
moduleB
}
})
在vue元件時,可以透過mapState取得state.moduleA的資料
computed:{
...mapState({
productA:(state)=>store.moduleA.product,
productB:(state)=>store.moduleB.product
})
}
拆成兩個模組後,可以透過rootState取得外層store的資料。
const moduleA= {
state: ()=>({...}),
getters: {
// 需透過第三和四的參數取得rootState、rootGetters
sumWithRootCount (state, getters, rootState) {
return state.count + rootState.count
}
},
mutations: {
//可以透過context存取context.rootState
increment ({state,commit,rootState}) {
//...
}
},
actions:{
//可以透過context存取context.rootState
incrementIfOddOnRootSum({ state, commit, rootState} = context;
if((state.count + rootState.count)% 2 === 1){
commit('increment')
}
}
}
}
當模組有相同名稱的actions時,
const moduleA = {
state: () => ({ ... }),
mutations: { ... },
actions: {
fetchProductInfo(){...}
},
}
const moduleB = {
state: () => ({ ... }),
mutations: { ... },
actions: {
fetchProductInfo(){...}
},
}
元件下dispatch時兩個會同時被呼叫
this.$store.dispatch('fetchProductInfo')
namespaced可以避免因相同命名而犯的錯誤。
const moduleA = {
namespaced: true,
state: () => ({ ... }),
mutations: { ... },
actions: {
fetchProductInfo(){...}
},
}
const moduleB = {
namespaced: true,
state: () => ({ ... }),
mutations: { ... },
actions: {
fetchProductInfo(){...}
},
}
呼叫的時候就不會找錯人
// moduleA 的 fetchProductInfo
this.$store.dispatch('moduleA/fetchProductInfo');
// moduleB 的 fetchProductInfo
this.$store.commit('moduleB/fetchProductInfo');
//OR 採用mapActions,mapMutations指定namespaced到第一個參數
methods: {
...mapActions('moduleA', ['fetchProductInfo', '...']),
...mapMutations('moduleB', ['updateProductInfo', '...']),
},
模組也有機會dispatch或commit到root,此時只需要加入第三個參數:
dispatch('someOtherActions', null, {root:true})
commit('someMutation', null, {root:true})
圖解 Vuex 統一狀態管理
https://chineseplease.moe/wp-content/uploads/2020/04/Vuex.png