Vue.js Vuex
▌Introduction
Vuex is the official state management package
for Vue.js.
▌Environment
▋Vue.js 2.5.11
▋Vue CLI 3.2.1
▋Vuex 3.0.01
▌Mutations
▋Commit Mutations with Payload
We can
commit Mutations with parameter, which is called Payload.
For
example, we increase the “count” by a value from Payload in the following Vuex
instance.
(PS. Payload is Object in most case.)
import Vue from 'vue';
import Vuex from 'vuex'
Vue.use(Vuex)
export const store = new
Vuex.Store({
state: {
count: 0
},
mutations: {
increment
(state, payload) {
if(payload)
state.count += payload;
else
state.count++;
},
//...skip
}
})
To commit
Mutations:
let amt = 10;
store.commit("increment", amt);
▋Use mapMutations to commit mutations
By
injecting the Vuex Store to components, we can map the component methods to
store.commit calls by mapMutations
helper.
▋Steps
1. Make sure injecting Store to components
new Vue({
el: '#app',
store,
//…
})
import { mapMutations } from "vuex";
var app = new Vue({
el: '#app',
methods: {
...mapMutations({
add: "increment", // Map
`this.add()` to `this.$store.commit('increment')`
minus: "decrement", // Map
`this.minus()` to `this.$store.commit('decrement')`
clear: "reset" // Map
`this.reset()` to `this.$store.commit('reset')`
})
},
})
▋Usage
this.add(10); //10 is the
optional payload
this.minus();
this.clear();
Of course
you can use the original name for the components methods:
methods: {
...mapMutations({
"increment", // Map
`this.increment()` to `this.$store.commit('increment')`
"decrement", // Map
`this.decrement()` to `this.$store.commit('decrement')`
"reset" // Map
`this.reset()` to `this.$store.commit('reset')`
})
}
▌Actions
▋Define Actions in Vuex Store
import Vue from 'vue';
import Vuex from 'vuex'
Vue.use(Vuex)
export const INCREMENT = 'increment';
export const DECREMENT = 'decrement';
export const RESET = 'reset';
export const store = new
Vuex.Store({
state: {
count: 0
},
mutations: {
increment
(state, payload) {
if(payload)
state.count += payload;
else state.count++;
},
decrement(state){
if(state.count
> 0)
state.count--;
},
reset(state){
state.count= 0;
}
},
actions: {
increment (context, payload) {
context.commit('increment', payload);
},
decrement(context){
context.commit('decrement');
},
reset(context){
context.commit('reset');
}
}
})
▋Usage: Dispatch
Action
//import singleton store
store.dispatch('increment',10); //10 is the
payload
store.dispatch('decrement');
//Injected store
this.$store.dispatch('increment',10); //10 is the
payload
this.$store.dispatch('decrement');
If the
Payload is Object, for example,
myPayload={amt:10}
Here are
three ways to dispatch the action,
//1.
store.dispatch('increment', myPayload)
//2.
store.dispatch('increment', {amt:10})
//3.
store.dispatch({
type: "increment",
amt: 10
});
▋Asynchronous Actions
Remeber that Mutations must be synchronous,
but Actions can be asynchronous?
Here is how to create asynchronous
Actions,
▋By promise
actions: {
increment
(context, payload) {
return new
Promise((resolve, reject) => {
setTimeout(() => {
context.commit('increment', payload);
resolve();
}, 3000)
})
},
//...
}
▋By async/await
actions: {
async increment
(context) {
context.commit('increment', await
getPayload());
}
//...
}
The getPayload
function is defined as following,
//Assume that getPayload() return promise as following
const getPayload = () => {
return new
Promise((resolve, reject) => {
setTimeout(() => {
resolve(10);
}, 3000)
})
}
▋Usage: Dispatch asynchronous Actions
store.dispatch("increment", amt).then(function(){
alert("Async
increment is done!");
});
▋ Use mapActions to dispatch actions
We can also
use mapActions
helper to map component methods to Actions.
The Vuex Store injection to
components is required.
import { mapActions } from "vuex";
var app = new Vue({
el: '#app',
methods: {
...mapActions({
add: "increment", // Map
`this.add()` to `this.$store.dispatch('increment')`
minus: "decrement", // Map
`this.add()` to `this.$store.dispatch('decrement')`
clear: "reset" // Map
`this.add()` to `this.$store.dispatch('reset')`
})
},
})
▋Usage: Dispatch Actions thru mapActions
this.add(10) //10 is
Payload
this.minus()
▌Getters
We can
use computed property to get or filter the State in Vuex Store, but the computed
property can only be used in the component. Vuex allows us to create Getters to reuse the
logics in other components.
▋Define Getters in Vuex Store
class ShopCart {
constructor() {
this.items = [];
this.totalCnt = 0; //Total
count for all items in shopcart
this.totalPrice
= 0; //Total pricing for all items in
shopcart
}
}
const store = new
Vuex.Store({
state: new ShopCart(),
mutations: {
//...skip
},
getters: {
totalCnt(state) {
return
state.totalCnt;
},
totalPrice(state) {
return
state.totalPrice;
},
item: (state) => (id) => {
return
state.items.find(x => x.id === id);
}
}
})
Notice
that if we want to pass the parameter(s) to Getters, define the Getter like
this,
(id is
the parameter)
item: (state) => (id) => {
return
state.items.find(x => x.id === id);
}
Which
equals to
item(state) {
return (id)
=> {
return
state.items.find(x => x.id === id);
}
}
▋Usage of Getters
let total = {
cnt: store.getters.totalCnt,
price: store.getters.totalPrice
};
let item = store.getters.item(this.targetId);
▋mapGetters
Furthermore,
we can map component methods to Vuex Getters by mapGetters
helper.
PS. Don’t
forget injecting Vuex Store to components
computed: {
// Other
computed props
...mapGetters({
totalCnt: "totalCnt",
totalPrice: "totalPrice",
targetItem: "item"
})
}
So that
we can use the Getters like computed properties,
console.info(this.totalCnt);
console.info(this.totalPrice);
let item = this.targetItem(this.targetId));
You can
use the default names of Getters for sure as below,
computed: {
// Other
computed props
...mapGetters([
"totalCnt","totalPrice","item"
])
}
▋Watch
changes of State
import { store, PUSH, PULL, CLEAR } from "../vuex/shopcart.store.js";+
import { mapGetters } from "vuex";
computed: {
...mapGetters({
currentUser: 'user',
}),
}
mounted() {
//
Watch the user store
store.watch( ()=> this.totalPrice, (newVal, oldVal) => {
// Do something
console.info(`${oldVal}->${newVal}`);
});
}
▌Reference
沒有留言:
張貼留言