最近進入了一個新項目組,前端框架選擇vue進行開發,數據的狀態管理選擇用vuex。本篇隨筆中的代碼採用vuex官網提供的購物車案例。html
├── index.html ├── main.js ├── api │ └── shop.js # 抽取出API請求 ├── components │ ├── App.vue # 根級別的頁面 │ ├── Cart.vue # 購物車組件 │ └── ProductList.vue # 產品組件 │ └── store ├── index.js # 咱們組裝模塊並導出 store 的地方 ├── actions.js # 根級別的 action ├── mutations.js # 根級別的 mutation ├── mutation-types.js # mutation事件類型 └── modules ├── cart.js # 購物車模塊 └── products.js # 產品模塊
Vuex有五個核心概念,分別是:State、Getter、Mutation、Action和Module前端
因爲Vuex的狀態存儲是響應式的,因此從store實例中讀取狀態最簡單的方式是在計算屬性中返回某個狀態vue
//product.js const state = { all: [{ 'id': 1, 'title': 'iPad 4 Mini', 'price': 500.01 },{ 'id': 2, 'title': 'H&M T-Shirt White', 'price': 10.99 }] } export default { state }
//productList.vue import store from '../store/index' <template> <ul> <li v-for="p in products"> {{ p.title }} - {{ p.price | currency }} </li> </ul> </template> <script> export default { computed: { products() { return store.state.all } }) } </script>
當一個組件須要獲取多個狀態時,能夠經過mapState
輔助函數幫助咱們生成計算屬性git
//改造productList.vue import { mapState } from 'vuex' export default { computed: mapState({ // 箭頭函數可以使代碼更簡練 products: state => state.all, // 傳字符串參數 'all' 等同於 `state => state.all` //products: 'all', // 爲了可以使用 `this` 獲取局部狀態,必須使用常規函數 /* products (state) { return state.all + this.localCount } */ }) }
若是計算屬性名和state子節點名字相同,也能夠傳遞一個字符串數組github
computed: mapState([ // 映射 this.all 爲 store.state.all 'all' ])
若是想要與局部計算屬性混合使用,則能夠經過對象展開運算符作到這一點vuex
computed: { localComputed () { /* ... */ }, // 使用對象展開運算符將此對象混入到外部對象中 ...mapState({ // ... }) }
Getter至關於store實例的計算屬性,Getter的返回值會根據它的依賴被緩存起來,只有依賴發生改變,纔會從新計算。
Getter接受State做爲第一個參數,其餘的getter做爲第二個參數,同時也會暴露爲store.getters對象api
//products.js const getters = { allProducts: (state, getter) => state.all } export default { state, getters }
//productList.vue computed: { allProducts() { return this.$store.getters.allProducts } }
一樣,Getter也有輔助函數mapGetters
,它的做用是將store中的getter映射到局部計算屬性,使用方法與mapState
同樣。數組
更改 Vuex 的 store 中的狀態的惟一方法是提交 Mutation。緩存
每一個 Mutation 都有一個字符串的 事件類型 (type) 和 一個回調函數(handler)。這個回調函數就是咱們實際進行狀態更改的地方,而且它會接受 state 做爲第一個參數,經過store.commit能夠傳遞第二個參數,也就是載荷(Payload)bash
// project.js // 可使用常量代替Mutation事件類型 const mutations = { [types.RECEIVE_PRODUCTS] (state, { products }) { state.all = products }, [types.ADD_TO_CART] (state, { id }) { state.all.find(p => p.id === id).inventory-- } } // actions const actions = { getAllProducts ({ commit }) { shop.getProducts(products => { commit(types.RECEIVE_PRODUCTS, { products }) }) } }
// mutation-types.js export const ADD_TO_CART = 'ADD_TO_CART' export const RECEIVE_PRODUCTS = 'RECEIVE_PRODUCTS'
Mutation也有輔助函數mapMutations
import { mapMutations } from 'vuex' export default { methods: { ...mapMutations([ 'increment', // 將 `this.increment()` 映射爲 `this.$store.commit('increment')` // `mapMutations` 也支持載荷: 'incrementBy' // 將 `this.incrementBy(amount)` 映射爲 `this.$store.commit('incrementBy', amount)` ]), ...mapMutations({ add: 'increment' // 將 `this.add()` 映射爲 `this.$store.commit('increment')` }) } }
Mutation必須是同步函數,若是想包含異步操做,那麼必需要使用Action
Action和Mutation有兩點不一樣:
actions: { getAllProducts ({ commit }) { commit('types.types.RECEIVE_PRODUCTS') } }
Action經過store.dispatch
方法觸發
store.dispatch('getAllProducts')
在組件中分發Action,咱們可使用mapActions
輔助函數將組件的methods映射爲store.dispatch
調用,使用方法同mapMutations
。
因爲使用單一狀態樹,應用的全部狀態會集中到一個比較大的對象。當應用變得很是複雜時,store 對象就有可能變得至關臃腫。
爲了解決以上問題,Vuex 容許咱們將 store 分割成模塊(module)。每一個模塊擁有本身的 state、mutation、action、getter、甚至是嵌套子模塊——從上至下進行一樣方式的分割:
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 的狀態
默認狀況下,模塊內部的action、mutation、getter是註冊在全局命名空間的,若是須要模塊被更好的封裝,那麼能夠經過添加namespaced: true
的方式使其成爲命名空間模塊
啓用了命名空間的 getter 和 action 會收到局部化的 getter
,dispatch
和 commit
。