1.簡介html
vuex是 vue官方推薦的一個狀態管理器。當咱們遇到不少狀態改變時,組件之間的通訊就會變得複雜,這時候vuex的強大就展示出來。vue
咱們從vuex的原理以及vuex的api兩個部分介紹vuexes6
原理:vuex
vuex的核心是store對象,它承載了vue的狀態管理。vuex的實現分爲了2個部分,第一個部分是store的建立,以及第二部分store的掛載,而且解析store。api
vuex經過插件安裝的形式來使得vue掛載vuex的store,固然這個是在vue組件的createBefore階段實現的。隨後Vuex將它直接掛載到 $options.$store 以供使用vue使用。數組
對於vuex的屬性,Vuex 會將 vuex 屬性解構成 getters 和 actions。並將 getters 的每一個屬性都掛載 vm 下(有可能被組件的 $options.data() 的屬性覆蓋),同時定義每一個值的 getter 方法,但並不會定義 setter 方法,這是由於根據 Vuex 的設計是不容許開發者直接在組件內更改 store.state,而對數據的改動要經過提交 mutation。Vuex 實際上將 vm.vuex.getter 內的屬性看成當前 vm 的計算屬性來處理。和計算屬性的區別是計算屬性依賴計算的是 vm.$options.data 內的值,而 vm.vuex.getter 的屬性依賴計算的是 store._vm.$options.data。這樣全部組件的渲染都將均可以直接從狀態樹拿數據來渲染 UI 。promise
全部的組件均可以和vuex的狀態樹進行數據交互。可是不容許直接改變狀態樹的狀態,應該用vuex的mutations來提交狀態的改變。vuex會將actions內的方法綁定到vue的$options.methods下,它們與vue中定義的方法並無區別。而 actions 內的方法將經過 dispatch 觸發 mutations 來更新全局狀態,actions方法與mutations的區別是,mutations改變state而且必須是同步改變,而actions能夠做爲異步提交的方法,dispatch 能夠接收一個promise,而且返回一個promise。異步
2.API:函數
state:在vue中引入store對象,在子組件中經過this.$store來訪問vuex中狀態,而且咱們最好在vue的computed中獲取vuex的狀態。this
mapState:這是一個語法糖,能夠快捷的獲取更多的state。
接受一個object參數:
// 在單獨構建的版本中輔助函數爲 Vuex.mapState import { mapState } from 'vuex' export default { // ... computed: mapState({ // 箭頭函數可以使代碼更簡練 count: state => state.count, // 傳字符串參數 'count' 等同於 `state => state.count` countAlias: 'count', // 爲了可以使用 `this` 獲取局部狀態,必須使用常規函數 countPlusLocalState (state) { return state.count + this.localCount } }) }
當計算屬性的名稱和節點名稱相同時,也能夠接受一個數組對象。
computed: mapState([ // 映射 this.count 爲 store.state.count 'count' ])
對象展開:合成最終的computed屬性
computed: { localComputed () { /* ... */ }, // 使用對象展開運算符將此對象混入到外部對象中 ...mapState({ // ... }) }
getter:store的計算屬性,在獲取數據的時候,咱們能夠經過getter進行數據的操做,在相同地方用到的數據操做就不須要寫一個公用的處理函數。它接受2個參數,state和getters。
getters: { // ... doneTodosCount: (state, getters) => { return getters.doneTodos.length } } store.getters.doneTodosCount // -> 1
mapGetters:
export default { // ... computed: { // 使用對象展開運算符將 getters 混入 computed 對象中 ...mapGetters([ 'doneTodosCount', 'anotherGetter', // ... ]) } }
或者
mapGetters({ // 映射 this.doneCount 爲 store.getters.doneTodosCount doneCount: 'doneTodosCount' })
mutations:vuex提交狀態的惟一方式。mutations更像一個事件監聽器,當vue中commit了信息以後,相應的mutation纔會執行相應的回掉函數。它接受2個參數,state和object。
由於vue是響應式的,因此mutations也應該遵照vue的動態綁定,因此在須要使用mutations前,儘可能初始化。或者是添加時使用vue.set(obj,'new obj', 'value')或者以新運算符state.obj = { ...state.obj, newProp: 123 }
mutations必須是同步函數
組件中提交mutations:
import { mapMutations } from 'vuex' export default { // ... methods: { ...mapMutations([ 'increment' // 映射 this.increment() 爲 this.$store.commit('increment') ]), ...mapMutations({ add: 'increment' // 映射 this.add() 爲 this.$store.commit('increment') }) } }
actions: actions提交的是mutations,由於mutations是必須爲同步狀態,actions就提供了一種異步的形式提交mutations,咱們能夠在active中去作異步處理,而且提交mutation。它接受一個context參數,這個參數具備store對象相同屬性和方法,可是並非store自己。
actions: { increment (context) { context.commit('increment') } }
//或者 使用解值
actions: {
increment ({ commit }) {
commit('increment')
}
}
actions以dispatch來分發
// 以載荷形式分發 store.dispatch('incrementAsync', { amount: 10 }) // 以對象形式分發 store.dispatch({ type: 'incrementAsync', amount: 10 })
組合的actions:
store.dispatch
能夠處理被觸發的action的回調函數返回的Promise,而且store.dispatch仍舊返回Promise
actions: { actionA ({ commit }) { return new Promise((resolve, reject) => { setTimeout(() => { commit('someMutation') resolve() }, 1000) }) } }
// 能夠這樣觸發
//一個 在不一樣模塊中能夠觸發多個 action 函數。在這種狀況下,只有當全部觸發函數完成後,返回的 Promise 纔會執行。
store.dispatch('actionA').then(() => {
// ... store.dispatch
})
// 也能夠這樣子觸發
actions: {
// ...
actionB ({ dispatch, commit }) {
return dispatch('actionA').then(() => {
commit('someOtherMutation')
})
}
}
modules:
Vuex 容許咱們將 store 分割到模塊(module)。每一個模塊擁有本身的 state、mutation、action、getters、甚至是嵌套子模塊——從上至下進行相似的分割。
const moduleA = { state: { ... }, mutations: { ... }, actions: { ... }, getters: { ... } } const moduleB = { state: { ... }, mutations: { ... }, actions: { ... } } const store = new Vuex.Store({ modules: { a: moduleA, b: moduleB } }) store.state.a // -> moduleA 的狀態 store.state.b // -> moduleB 的狀態
模塊的局部狀態
對於模塊內部的 mutation 和 getter,接收的第一個參數是模塊的局部狀態。
const moduleA = { state: { count: 0 }, mutations: { increment (state) { // state 模塊的局部狀態 state.count++ } }, getters: { doubleCount (state) { return state.count * 2 } } }
對於模塊內部的 action,context.state
是局部狀態,根節點的狀態是 context.rootState。
const moduleA = { // ... actions: { incrementIfOddOnRootSum ({ state, commit, rootState }) { if ((state.count + rootState.count) % 2 === 1) { commit('increment') } } } }
對於模塊內部的 getter,根節點狀態會做爲第三個參數。
const moduleA = { // ... getters: { sumWithRootCount (state, getters, rootState) { return state.count + rootState.count } } }
命名空間:
模塊內部的 action、mutation、和 getter 如今仍然註冊在全局命名空間——這樣保證了多個模塊可以響應同一 mutation 或 action。你能夠經過添加前綴或後綴的方式隔離各模塊,以免名稱衝突。你也可能但願寫出一個可複用的模塊,其使用環境不可控。例如,咱們想建立一個 todos
模塊:
// types.js // 定義 getter、action、和 mutation 的名稱爲常量,以模塊名 `todos` 爲前綴 export const DONE_COUNT = 'todos/DONE_COUNT' export const FETCH_ALL = 'todos/FETCH_ALL' export const TOGGLE_DONE = 'todos/TOGGLE_DONE' // modules/todos.js import * as types from '../types' // 使用添加了前綴的名稱定義 getter、action 和 mutation const todosModule = { state: { todos: [] }, getters: { [types.DONE_COUNT] (state) { // ... } }, actions: { [types.FETCH_ALL] (context, payload) { // ... } }, mutations: { [types.TOGGLE_DONE] (state, payload) { // ... } } }
咱們也能夠運用es6的新方法,symbol作命名;
須要瞭解更多關於symbol的信息,請移步阮一峯老師的ES6
參考文獻: