安裝vuex
npm install --save vuex
基本的vuex引入
// ./store/store.js
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
export const store = new Vuex.Store({
state: {
counter : 0
},
getters: {
getCounter: state => { return state.counter; },
getCounterStr: state => { return state.counter + ' counts'; }
},
mutations: {
increment: state => { state.counter++; },
decrement: state => { state.counter--; },
},
// actions
})
// ./main.js
import Vue from 'vue'
import App from './App.vue'
import {store} from './store/store'
new Vue({
el: '#app',
store,
render: h => h(App)
})
state和getters及使用mapGetters配合ES6的object spread方式取store裡面state的值
import { mapGetters } from "vuex";
export default {
computed: {
...mapGetters(["getCounter", "getCounterStr"]),
counter(){
return this.$store.getters.getCounter;
// return this.$store.state.counter;
}
}
};
如果是用CLI2且要在專案裡面使用object spread這功能,我們會需要引入babel-preset-stage-2
npm install --save-dev babel-preset-stage-2
// .babelrc
{
"presets": [["es2015", { "modules": false }], ["stage-2"]]
}
mutations同樣也有mapMutations可以使用
import { mapMutations } from "vuex";
export default {
methods: {
...mapMutations(["increment", "decrement"])
}
};
mutations不能在非同步的狀態下呼叫。假設 mutations裡面的increment是在setTimeout裡面,過1秒後才呼叫callback去改state.counter,如果同時有多個元件呼叫increment,那麼state.counter的狀態將會錯亂,所以mutations建議只在同步底下呼叫。這時候我們可以使用actions,而也是一個好的習慣不管同步非同步都是先call actions,然後在從actions裡面去commit mutations。
// actions
increment: context => {
context.commit('increment');
},
decrement: ({commit}) => {
commit('decrement');
},
asyncIncrement: ({commit}) => {
setTimeout(() => {
commit('increment');
}, 1000);
},
asyncDecrement: ({commit}) => {
setTimeout(() => {
commit('decrement');
}, 1000);
}
actions 回傳一個callback function帶著context參數 (如increment),我們也可以用ES6的語法省略掉context,直接使用commit。當然 actions也有mapActions可以使用。
import { mapActions } from "vuex";
export default {
methods: {
...mapActions (["increment", "decrement"])
}
};
mutations, actions帶參數的寫法。payload可以是值也可以是物件
// mutations
increment: (state, payload) => { state.counter += payload; }
// actions
increment: ({commit}, payload) => { commit('increment'); }
// template
<button @click="increment(10)">Increment</button>
<!-- <button @click="increment({'by':10, 'duration': 1000})">Increment</button> -->
如果要使用two-way-binding如v-model,那原本的computed method可以做以下修改。
computed: {
counter(){
get(){
return this.$store.getters.getCounter;
},
set(value){
// pretend updateValue is a method inside actions
this.$store.dispatch('updateValue', value);
}
}
}
我們可以把new Vuex.Store({…})裡面的getters, mutations…等方法以模塊的方式引入,詳情參考這裡。
如果使用模塊方式引入,那在getters, mutations, actions…等裡面的方法名稱有可能重複,這時候可以使用namespacing的方式解決,詳情參考這裡。
Reference
- https://vuex.vuejs.org/zh/guide/
- https://github.com/vuejs/vuex/releases/tag/v2.1.0