官方定義#
Vuex 是一個專為 Vue.js 應用程序開發的狀態管理模式。它採用集中式存儲管理應用的所有組件的狀態,並以相應的規則保證狀態以一種可預測的方式發生變化。
注入 vuex#
import store from "./store";
new Vue({
store,
});
store.js
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
export default new Vuex.Store({
state: {
msg: "hello world",
},
mutations: {},
actions: {},
});
獲取狀態#
這樣在任何一個組件裡,都可以這樣獲取到這個 msg
<template>
<div class="about">
<h1>這是一個關於頁面</h1>
<h2>{{$store.state.msg}}</h2>
</div>
</template>
修改狀態#
讓 mutations
提供一個修改狀態的方法
mutations: {
setMsg(state, newMsg) {
state.msg = newMsg
}
}
再讓 actions
來提交修改的請求
actions: {
setMsg ({ commit }) {
commit('setMsg', 'hello')
}
}
修改的動作,在其它組件裡去觸發
<template>
<div class="about">
<h1>這是一個關於頁面</h1>
<h2>{{$store.state.msg}}</h2>
</div>
</template>
<script>
export default {
mounted () {
this.$store.dispatch('setMsg')
}
}
</script>
思考#
上例屬於簡單的狀態管理,state
在存放狀態、mutations
提供了修改狀態的方法、actions
負責觸發修改狀態的方法,並提交修改的數據;上例 actions
裡是手動修改的數據,工作中應該是提交請求的數據。但是上例中有個明顯的問題,誰都可以修改(dispatch
)狀態。
命名空間#
如果項目足夠複雜,那麼可以使用 vuex 提供的命名空間來修改狀態。使用的前提還需要使用 vuex
的 modules
。modules
是一個對象,其結構也是由state
、 mutations
、actions
組成。區別是它多了一個namespaced
屬性,以此來使用命名空間。
修改狀態的三種方法#
dispatch#
先把原來寫的內容提取到一個 modules
裡
store.js
import Vue from "vue";
import Vuex from "vuex";
import home from "./modules/home";
Vue.use(Vuex);
export default new Vuex.Store({
modules: {
home,
},
});
./modules/home.js
export default {
namespaced: true,
state: {
msg: "hello world",
},
actions: {
setMsg({ commit }) {
commit("setMsg", "hello");
},
},
mutations: {
setMsg(state, newMsg) {
state.msg = newMsg;
},
},
};
最後取狀態和修改狀態
<template>
<div class="about">
<h1>這是一個關於頁面</h1>
<h2>{{$store.state.home.msg}}</h2>
</div>
</template>
<script>
export default {
mounted () {
this.$store.dispatch('home/setMsg')
}
}
</script>
觀察最後修改時和之前的不同,無非是取狀態和修改狀態都多了一層 home
,提高了一定的使用門檻。儘管這樣,但至少可以識別操作的是哪個模塊的狀態。
上例再通過 modules
修改 狀態還有另一種等價的寫法
mapActions#
<template>
<div class="about">
<h1>這是一個關於頁面</h1>
<h2>{{$store.state.home.msg}}</h2>
</div>
</template>
<script>
import { mapActions } from 'vuex'
export default {
methods: {
...mapActions('home', ['setMsg'])
},
mounted () {
this.setMsg()
}
}
</script>
mapActions
執行完後返回的是一個對象,通過擴展運算法展開後,會在當前實例裡添加一個 setMsg 方法。調用這個方法就會觸發狀態的修改。
createNamespacedHelpers#
上面兩個方法都有一個很明顯的問題,如果在當前組件裡,需要修改的狀態有很多個。那麼就意味著有很多層 home
。通過 vuex
的 createNamespacedHelpers
方法,可以很友好的解決這個問題。
<template>
<div class='about'>
<h1>這是一個關於頁面</h1>
<h2>{{$store.state.home.msg}}</h2>
</div>
</template>
<script>
import { createNamespacedHelpers } from 'vuex'
const { mapActions } = createNamespacedHelpers('home')
export default {
methods: {
...mapActions(['setMsg'])
},
mounted () {
this.setMsg()
}
}
</script>
簡化取值#
之前的例子一直沒有提到取值的問題,實際工作中也不推薦那麼去做;vuex
提供了一個 mapState 的方法,可以簡化取值。
<template>
<div class='about'>
<h1>這是一個關於頁面</h1>
<h2>{{msg}}</h2>
</div>
</template>
<script>
import { createNamespacedHelpers } from 'vuex'
const { mapActions, mapState } = createNamespacedHelpers('home')
export default {
computed: {
...mapState(['msg'])
},
methods: {
...mapActions(['setMsg'])
},
mounted () {
this.setMsg()
}
}
</script>
提取變量#
回憶一下 setMsg
這個字眼出現的次數,在組件裡使用出現過,在 store
或 modules
裡出現過。這時提倡的做法,就是將這個 setMsg
提取出來,用一個常量保存;
./store/action-type.js
export const SET_MSG = "setMsg";
使用的時候,儘量避免直接使用 setMsg
,這樣便於自己或其他人去維護。
總結#
vuex
的便利性不言而喻,根據項目的複雜度,它提供了漸進增強的方案。當項目很簡單時,不用 modules
就能解決基本需求。如果複雜度上升了,modules
自然是不二選擇。如果模塊的個數並不多,大可只用 dispatch
。即便模塊多了起來,createNamespacedHelpers
也為後續工作鋪好了路。