Vuex

298 阅读1分钟

在全局的vue对象注入store,通过this.$store.state访问

new Vue({
  el: '#app',
  // 把 store 对象提供给 “store” 选项,这可以把 store 的实例注入所有的子组件
  store,
  template: `
    <div class="app">
      <counter></counter>
    </div>
  `
})

State

mapState
state: {...}
     
computed: {
  ...mapState({
    // 箭头函数可使代码更简练
    count: state => state.count,

    // 传字符串参数 'count' 等同于 `state => state.count`
    countAlias: 'count',

    // 为了能够使用 `this` 获取局部状态,必须使用常规函数
    countPlusLocalState (state) {
      return state.count + this.localCount
    }
 })
 // 计算属性的名称与 state 的子节点名称相同时
 ...mapState([
   // 映射 this.count 为 store.state.count
  'count'
 ])
}

Getters

mapGetters
getters: {
  // 属性访问
  doneTodosCount: (state, getters) => {
    return getters.doneTodos.length
  },
  // 方法访问
  getTodoById: (state) => (id) => {
    return state.todos.find(todo => todo.id === id)
  }
}

// 方法访问
this.$store.getters.getTodoById(2)

computed: {
  ...mapGetters([
    'doneTodosCount'
  ])
  ...mapGetters({
    // 把 `this.doneCount` 映射为 `this.$store.getters.doneTodosCount`
    doneCount: 'doneTodosCount'
  })
  // 属性访问
  doneTodosCount () {
    return this.$store.getters.doneTodosCount
  }
}

Mutations

mapMutations
// 整个 app 包含的 mutation 一目了然
export const SOME_MUTATION = 'SOME_MUTATION'

import { SOME_MUTATION } from './mutation-types'
mutations: {
   increment (state, payload) {
     state.count += payload.amount
   },
   [SOME_MUTATION] (state) {
      // mutate state
    }
 }
computed: {
  ...mapMutations(['increment']) // 将 `this.increment()` 映射为 `this.$store.commit('increment')`
  ...mapMutations({
    add: 'increment' // 将 `this.add()` 映射为 `this.$store.commit('increment')`
  })

this.$store.commit('increment', { amount: 10})
this.$store.commit({
  type: 'increment',
  amount: 10
})

Actions

mapActions 分发mutation
actions: {
    // 接受一个与 store 实例具有相同方法和属性的 context 对象,因此你可以调用context.commit 提交一个 mutation
  checkout ({ commit, state }, products) {
    // 把当前购物车的物品备份起来
    const savedCartItems = [...state.cart.added]
    // 发出结账请求,然后乐观地清空购物车
    commit(types.CHECKOUT_REQUEST)
    // 购物 API 接受一个成功回调和一个失败回调
    shop.buyProducts(
      products,
      // 成功操作
      () => commit(types.CHECKOUT_SUCCESS),
      // 失败操作
      () => commit(types.CHECKOUT_FAILURE, savedCartItems)
    )
  }
}

this.$store.dispatch('checkout', { amount: 10 })

Modules

// namespaced: true 所有 getter、action 及 mutation 都会自动根据模块注册的路径调整命名

// root: true
dispatch('someOtherAction', null, { root: true }) // -> 'someOtherAction'
dispatch('someOtherAction') // -> 'foo/someOtherAction'

foo: {
  namespaced: true,
  actions: {
    someAction: {
      root: true,
      handler (namespacedContext, payload) { ... } // -> 'someAction'
    }
  }
}

const moduleA = {
  state: () => ({ ... }),
  mutations: { ... },
  actions: { ... },
  getters: { ... }
}

const moduleB = {
  namespaced: true,
  state: () => ({ ... }),
  getters: {
    popular () { ... } // -> store.getters['b/popular']
  }        
  mutations: { ... },
  actions: {
    incrementIfOddOnRootSum ({ state, commit, rootState }) {
      if ((state.count + rootState.count) % 2 === 1) {
        commit('increment')
      }
    }
  }
}

const store = new Vuex.Store({
  modules: {
    a: moduleA,
    b: moduleB
  }
})

store.state.a // -> moduleA 的状态
store.state.b // -> moduleB 的状态

// 简写
...mapActions([
  'some/nested/module/foo', // -> this['some/nested/module/foo']()
  'some/nested/module/bar' // -> this['some/nested/module/bar']()
])

...mapState('some/nested/module', {
  a: state => state.a,
  b: state => state.b
})

const { mapState, mapActions } = createNamespacedHelpers('some/nested/module')