Getter基础 #
什么是 Getter? #
Getter 类似于 Vue 组件中的计算属性,用于从 store 的 state 中派生出一些状态。Getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。
定义 Getter #
基本语法 #
javascript
const store = createStore({
state: {
todos: [
{ id: 1, text: 'Learn Vuex', done: true },
{ id: 2, text: 'Build App', done: false }
]
},
getters: {
// 接收 state 作为第一个参数
doneTodos: state => {
return state.todos.filter(todo => todo.done)
}
}
})
访问其他 Getter #
Getter 可以接收其他 getter 作为第二个参数:
javascript
const store = createStore({
state: {
todos: [
{ id: 1, text: 'Learn Vuex', done: true },
{ id: 2, text: 'Build App', done: false }
]
},
getters: {
doneTodos: state => {
return state.todos.filter(todo => todo.done)
},
// 使用其他 getter
doneTodosCount: (state, getters) => {
return getters.doneTodos.length
}
}
})
访问 Getter #
通过属性访问 #
javascript
// 在组件中
this.$store.getters.doneTodos
// 在计算属性中
computed: {
doneTodos() {
return this.$store.getters.doneTodos
}
}
通过 mapGetters 辅助函数 #
javascript
import { mapGetters } from 'vuex'
export default {
computed: {
// 数组语法
...mapGetters([
'doneTodos',
'doneTodosCount'
])
}
}
重命名映射 #
javascript
import { mapGetters } from 'vuex'
export default {
computed: {
// 对象语法:重命名
...mapGetters({
completedTodos: 'doneTodos',
completedCount: 'doneTodosCount'
})
}
}
Getter 传参 #
返回函数 #
Getter 本身不能接收参数,但可以让 getter 返回一个函数:
javascript
const store = createStore({
state: {
todos: [
{ id: 1, text: 'Learn Vuex', done: true },
{ id: 2, text: 'Build App', done: false }
]
},
getters: {
// 返回一个函数
getTodoById: state => id => {
return state.todos.find(todo => todo.id === id)
}
}
})
// 使用
this.$store.getters.getTodoById(1)
// { id: 1, text: 'Learn Vuex', done: true }
实际应用 #
javascript
getters: {
// 按类型筛选产品
productsByCategory: state => category => {
return state.products.filter(p => p.category === category)
},
// 按价格范围筛选
productsByPriceRange: state => (min, max) => {
return state.products.filter(p => p.price >= min && p.price <= max)
},
// 检查用户权限
hasPermission: state => permission => {
return state.user.permissions.includes(permission)
}
}
// 使用
this.$store.getters.productsByCategory('electronics')
this.$store.getters.productsByPriceRange(100, 500)
this.$store.getters.hasPermission('admin')
常见使用场景 #
1. 列表过滤 #
javascript
state: {
products: [
{ id: 1, name: 'Product 1', price: 100, inStock: true },
{ id: 2, name: 'Product 2', price: 200, inStock: false },
{ id: 3, name: 'Product 3', price: 150, inStock: true }
]
},
getters: {
inStockProducts: state => {
return state.products.filter(p => p.inStock)
},
outOfStockProducts: state => {
return state.products.filter(p => !p.inStock)
},
productsByPrice: state => {
return [...state.products].sort((a, b) => a.price - b.price)
}
}
2. 数据转换 #
javascript
state: {
users: [
{ firstName: 'John', lastName: 'Doe' },
{ firstName: 'Jane', lastName: 'Smith' }
]
},
getters: {
userFullNames: state => {
return state.users.map(user => ({
...user,
fullName: `${user.firstName} ${user.lastName}`
}))
},
userOptions: state => {
return state.users.map(user => ({
label: `${user.firstName} ${user.lastName}`,
value: user.id
}))
}
}
3. 统计计算 #
javascript
state: {
cart: [
{ productId: 1, quantity: 2, price: 100 },
{ productId: 2, quantity: 1, price: 200 }
]
},
getters: {
cartTotal: state => {
return state.cart.reduce((total, item) => {
return total + item.price * item.quantity
}, 0)
},
cartItemCount: state => {
return state.cart.reduce((count, item) => {
return count + item.quantity
}, 0)
},
averageItemPrice: (state, getters) => {
if (getters.cartItemCount === 0) return 0
return getters.cartTotal / getters.cartItemCount
}
}
4. 条件判断 #
javascript
state: {
user: {
name: 'John',
role: 'admin',
permissions: ['read', 'write', 'delete']
}
},
getters: {
isLoggedIn: state => state.user !== null,
isAdmin: state => state.user?.role === 'admin',
canEdit: state => {
return state.user?.permissions.includes('write')
},
canDelete: state => {
return state.user?.permissions.includes('delete')
}
}
组合式 API 中使用 #
基本用法 #
vue
<script>
import { computed } from 'vue'
import { useStore } from 'vuex'
export default {
setup() {
const store = useStore()
return {
doneTodos: computed(() => store.getters.doneTodos),
doneTodosCount: computed(() => store.getters.doneTodosCount)
}
}
}
</script>
封装 mapGetters #
javascript
// composables/useMapGetters.js
import { computed } from 'vue'
import { useStore } from 'vuex'
export function useMapGetters(getters) {
const store = useStore()
const result = {}
if (Array.isArray(getters)) {
getters.forEach(name => {
result[name] = computed(() => store.getters[name])
})
} else {
Object.keys(getters).forEach(key => {
result[key] = computed(() => store.getters[getters[key]])
})
}
return result
}
使用封装 #
vue
<script>
import { useMapGetters } from '@/composables/useMapGetters'
export default {
setup() {
const { doneTodos, doneTodosCount } = useMapGetters([
'doneTodos',
'doneTodosCount'
])
return {
doneTodos,
doneTodosCount
}
}
}
</script>
最佳实践 #
1. 保持 Getter 纯净 #
javascript
// 推荐:纯函数
getters: {
doubleCount: state => state.count * 2
}
// 不推荐:有副作用
getters: {
doubleCount: state => {
console.log('computed') // 副作用
return state.count * 2
}
}
2. 合理使用缓存 #
javascript
// Getter 会缓存结果
getters: {
expensiveCalculation: state => {
// 复杂计算,但会缓存
return state.items.reduce(/* ... */)
}
}
// 如果不需要缓存,使用方法
methods: {
calculate() {
// 每次调用都会执行
return this.$store.state.items.reduce(/* ... */)
}
}
3. 避免在 Getter 中修改状态 #
javascript
// 错误:在 getter 中修改状态
getters: {
getAndIncrement: state => {
state.count++ // 不要这样做
return state.count
}
}
// 正确:通过 mutation 修改
getters: {
count: state => state.count
},
mutations: {
INCREMENT(state) {
state.count++
}
}
总结 #
Getter 的核心要点:
| 特性 | 说明 |
|---|---|
| 缓存 | 依赖不变时返回缓存结果 |
| 传参 | 返回函数实现参数传递 |
| 链式 | Getter 可以访问其他 Getter |
| 纯净 | 不应有副作用 |
继续学习 mapGetters辅助函数,深入了解 Getter 映射技巧。
最后更新:2026-03-28