Vuex 是 Vue.js 用來管理不同 Component 間狀態的一個函式庫
Vue.js 的狀態管理流程主要可以分為下面三個部分:
1 State: 用來驅動應用的資料來源
2 View: 用宣告式將State對應到視圖
3 Actions: 響應在View上使用者輸入導致的狀態變化
以程式碼來看如下:
new Vue({
// state
data () {
return {
count: 0
}
},
// view
template: `
<div>{{ count }}</div>
`,
// actions
methods: {
increment () {
this.count++
}
}
})
以上三者的互動流程可以以下圖來呈現:
但當多個 Component 需要共享狀態的時候
以上的單向流狀態管理得簡潔性就容易被破壞,主要的問題有以下二個:
1 多個 View 依賴於同一個 State
2 多個 Action 要修改同一個 State
對於問題1 多個View 依賴於同一個 State,會需要使用巢狀的Component寫法
並且如果需要透過props傳遞狀態到sibling Component會很不方便
對於問題2 多個 Action 要修改同一個State,
會采用父子Component直接引用或者通過事件来變更和同步狀態的多份Copy
以上這兩種做法都會造成程式不易維護
Vuex把所有共用的State抽取出來成為一個global的Store,
每個Component共享這個Store,不能直接修改Store
只能透過Commit去發起修改
範例參考
HTML部分:
<div id="app"/>
Javascript的部分:
Vue.use(Vuex);
let store = new Vuex.Store({
state: {
count: 1
},
actions: {
incrementCount(context, counting) {
context.commit('INCREMENET_COUNT', counting);
}
},
mutations: {
INCREMENET_COUNT(state, counting) {
state.count += counting;
}
}
});
Vue.component('counter', {
template: `<div>
<p>{{count}}</p>
<button @click="increase">Click Me</button>
</div>`,
computed: {
count() {
return this.$store.state.count;
}
},
methods: {
increase() {
this.$store.dispatch('incrementCount', 1);
}
}
});
let vm = new Vue({
el: '#app',
template: `<counter/>`,
store
});
然而上面的用法會有一些問題
由於是全域的store 因此可能會有 命名衝突
所以比較好的做法是透過 namespace屬性分隔 不同store
每個store以module方始載入
並且用mapState把每個 store指定到對應 state名稱