// 在单独构建的版本中辅助函数为 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 } }) }
当映射的计算属性的名称与 state 的子节点名称相同时,也可以给 mapState 传一个字符串数组
computed: mapState([ // 映射 this.count 为 store.state.count 'count' ])
对象展开运算符mapState 函数返回的是一个对象。如何将它与局部计算属性混合使用呢?通常,需要使用一个工具函数将多个对象合并为一个,将最终对象传给 computed 属性。但是自从有了对象展开运算符,可以极大地简化写法:
computed: { localComputed () { /* ... */ }, // 使用对象展开运算符将此对象混入到外部对象中 ...mapState({ // ... }) }
组件仍然保有局部状态使用 Vuex 并不意味着需要将所有的状态放入 Vuex。虽然将所有的状态放到 Vuex 会使状态变化更显式和易调试,但也会使代码变得冗长和不直观。如果有些状态严格属于单个组件,最好还是作为组件的局部状态
Getter有时候需要从 store 中的 state 中派生出一些状态,例如对列表进行过滤并计数:
computed: { doneTodosCount () { return this.$store.state.todos.filter(todo => todo.done).length } }
如果有多个组件需要用到此属性,要么复制这个函数,或者抽取到一个共享函数然后在多处导入它——无论哪种方式都不是很理想
Vuex 允许在 store 中定义“getter”(可以认为是 store 的计算属性)。就像计算属性一样,getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算
Getter 接受 state 作为其第一个参数:
const store = new Vuex.Store({ state: { todos: [ { id: 1, text: '...', done: true }, { id: 2, text: '...', done: false } ] }, getters: { doneTodos: state => { return state.todos.filter(todo => todo.done) } } })
Getter 会暴露为 store.getters 对象:
store.getters.doneTodos // -> [{ id: 1, text: '...', done: true }]
Getter 也可以接受其他 getter 作为第二个参数:
getters: { // ... doneTodosCount: (state, getters) => { return getters.doneTodos.length } } store.getters.doneTodosCount // -> 1
可以很容易地在任何组件中使用它:
computed: { doneTodosCount () { return this.$store.getters.doneTodosCount } }
也可以通过让 getter 返回一个函数,来实现给 getter 传参。在对 store 里的数组进行查询时非常有用
getters: { // ... getTodoById: (state, getters) => (id) => { return state.todos.find(todo => todo.id === id) } } store.getters.getTodoById(2) // -> { id: 2, text: '...', done: false }
如果箭头函数不好理解,翻译成普通函数如下
var getTodoById = function(state,getters){ return function(id){ return state.todos.find(function(todo){ return todo.id === id }) } } store.getters.getTodoById(2) // -> { id: 2, text: '...', done: false }
mapGetters辅助函数mapGetters 辅助函数仅仅是将 store 中的 getter 映射到局部计算属性:
import { mapGetters } from 'vuex' export default { // ... computed: { // 使用对象展开运算符将 getter 混入 computed 对象中 ...mapGetters([ 'doneTodosCount', 'anotherGetter', // ... ]) } }
如果想将一个 getter 属性另取一个名字,使用对象形式:
mapGetters({ // 映射 `this.doneCount` 为 `store.getters.doneTodosCount` doneCount: 'doneTodosCount' })
mutation更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)。这个回调函数就是实际进行状态更改的地方,并且它会接受 state 作为第一个参数:
const store = new Vuex.Store({ state: { count: 1 }, mutations: { increment (state) { // 变更状态 state.count++ } } })
不能直接调用一个 mutation handler。这个选项更像是事件注册:“当触发一个类型为 increment 的 mutation 时,调用此函数。”要唤醒一个 mutation handler,需要以相应的 type 调用 store.commit 方法:
store.commit('increment')
提交载荷(Payload)可以向 store.commit 传入额外的参数,即 mutation 的 载荷(payload)
// ... mutations: { increment (state, n) { state.count += n } } store.commit('increment', 10)
在大多数情况下,载荷应该是一个对象,这样可以包含多个字段并且记录的 mutation 会更易读:
// ... mutations: { increment (state, payload) { state.count += payload.amount } } store.commit('increment', { amount: 10 })
对象风格的提交方式提交 mutation 的另一种方式是直接使用包含 type 属性的对象
store.commit({ type: 'increment', amount: 10 })
当使用对象风格的提交方式,整个对象都作为载荷传给 mutation 函数,因此 handler 保持不变:
mutations: { increment (state, payload) { state.count += payload.amount } }
遵守响应规则