Getter 派生

Getter 类似于计算属性,用于从 store 的 state 中派生出新的状态。当多个组件需要对相同状态进行相同处理时,Getter 特别有用。

基本用法

定义 Getter

const store = new Vuex.Store({
  state: {
    todos: [
      { id: 1, text: '学习 Vue', done: true },
      { id: 2, text: '学习 Vuex', done: false },
      { id: 3, text: '学习 Router', done: true }
    ]
  },
  getters: {
    doneTodos: state => {
      return state.todos.filter(todo => todo.done)
    }
  }
})

访问 Getter

this.$store.getters.doneTodos

Getter 参数

state 参数

getters: {
  doneTodos: state => {
    return state.todos.filter(todo => todo.done)
  }
}

getters 参数

Getter 可以访问其他 getter:

getters: {
  doneTodos: state => {
    return state.todos.filter(todo => todo.done)
  },
  doneTodosCount: (state, getters) => {
    return getters.doneTodos.length
  }
}

返回函数

Getter 可以返回一个函数,实现参数化查询:

getters: {
  getTodoById: state => id => {
    return state.todos.find(todo => todo.id === id)
  }
}
this.$store.getters.getTodoById(1)

mapGetters 辅助函数

数组形式

import { mapGetters } from 'vuex'

export default {
  computed: {
    ...mapGetters(['doneTodos', 'doneTodosCount'])
  }
}

对象形式

import { mapGetters } from 'vuex'

export default {
  computed: {
    ...mapGetters({
      completedTodos: 'doneTodos',
      completedCount: 'doneTodosCount'
    })
  }
}

实战示例

用户相关

getters: {
  isLoggedIn: state => !!state.token,
  
  userName: state => state.user?.name || '游客',
  
  isAdmin: state => state.user?.role === 'admin',
  
  userDisplayName: state => {
    if (!state.user) return '游客'
    return state.user.nickname || state.user.name || '未设置昵称'
  }
}

购物车相关

getters: {
  cartItems: state => state.cart.items,
  
  cartTotal: state => {
    return state.cart.items.reduce((total, item) => {
      return total + item.price * item.quantity
    }, 0)
  },
  
  cartCount: state => {
    return state.cart.items.reduce((count, item) => {
      return count + item.quantity
    }, 0)
  },
  
  hasItems: state => state.cart.items.length > 0,
  
  getItemById: state => id => {
    return state.cart.items.find(item => item.id === id)
  }
}

过滤和搜索

getters: {
  filteredProducts: state => {
    let products = state.products
    
    if (state.filters.category) {
      products = products.filter(p => p.category === state.filters.category)
    }
    
    if (state.filters.priceRange) {
      const [min, max] = state.filters.priceRange
      products = products.filter(p => p.price >= min && p.price <= max)
    }
    
    if (state.searchQuery) {
      const query = state.searchQuery.toLowerCase()
      products = products.filter(p => 
        p.name.toLowerCase().includes(query) ||
        p.description.toLowerCase().includes(query)
      )
    }
    
    return products
  },
  
  productCount: (state, getters) => getters.filteredProducts.length
}

分页数据

getters: {
  paginatedList: state => {
    const { page, pageSize } = state.pagination
    const start = (page - 1) * pageSize
    const end = start + pageSize
    return state.items.slice(start, end)
  },
  
  totalPages: state => {
    return Math.ceil(state.pagination.total / state.pagination.pageSize)
  },
  
  hasNextPage: (state, getters) => {
    return state.pagination.page < getters.totalPages
  },
  
  hasPrevPage: state => {
    return state.pagination.page > 1
  }
}

统计数据

getters: {
  totalRevenue: state => {
    return state.orders.reduce((sum, order) => sum + order.total, 0)
  },
  
  averageOrderValue: (state, getters) => {
    if (state.orders.length === 0) return 0
    return getters.totalRevenue / state.orders.length
  },
  
  ordersByStatus: state => {
    return state.orders.reduce((acc, order) => {
      const status = order.status
      acc[status] = (acc[status] || 0) + 1
      return acc
    }, {})
  }
}

权限检查

getters: {
  permissions: state => state.user?.permissions || [],
  
  hasPermission: (state, getters) => permission => {
    return getters.permissions.includes(permission)
  },
  
  hasAnyPermission: (state, getters) => permissions => {
    return permissions.some(p => getters.permissions.includes(p))
  },
  
  hasAllPermissions: (state, getters) => permissions => {
    return permissions.every(p => getters.permissions.includes(p))
  }
}

Getter 缓存

Getter 会缓存结果,只有依赖的 state 变化时才重新计算:

getters: {
  expensiveGetter: state => {
    console.log('计算中...')
    return state.items.map(item => {
      // 复杂计算
      return processedItem
    })
  }
}

多次访问只计算一次:

console.log(this.$store.getters.expensiveGetter)
console.log(this.$store.getters.expensiveGetter)

Getter vs 计算属性

特性Getter计算属性
定义位置store组件
访问范围全局组件内
缓存
参数支持返回函数不支持
适用场景跨组件复用组件私有

组合 Getter

getters: {
  activeUsers: state => state.users.filter(u => u.active),
  
  adminUsers: state => state.users.filter(u => u.role === 'admin'),
  
  activeAdmins: (state, getters) => {
    return getters.activeUsers.filter(u => u.role === 'admin')
  }
}

小结

Getter 要点:

  1. 派生状态:从 state 计算新状态
  2. 缓存机制:依赖不变则不重新计算
  3. 参数支持:返回函数实现参数化
  4. 辅助函数:mapGetters 简化访问
  5. 组合使用:Getter 可以依赖其他 Getter