初識vuex

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

 

參考文獻:

vuex文檔

爲何 Vuex 比 Redux 更適合 Vue.js

相關文章
相關標籤/搜索