Getters 计算属性 #
什么是 Getters? #
Getters 类似于 Vue 的 computed 属性,用于定义派生状态。它们会自动缓存计算结果,只有依赖的状态变化时才会重新计算。
定义 Getters #
基本语法 #
ts
export const useCounterStore = defineStore('counter', {
state: () => ({
count: 0
}),
getters: {
// 箭头函数
doubleCount: (state) => state.count * 2,
// 带类型的箭头函数
tripleCount: (state): number => state.count * 3
}
})
访问 State #
ts
export const useUserStore = defineStore('user', {
state: () => ({
firstName: 'John',
lastName: 'Doe'
}),
getters: {
// 使用 state 参数
fullName: (state) => `${state.firstName} ${state.lastName}`
}
})
访问其他 Getter #
使用 this 访问其他 getter:
ts
export const useCounterStore = defineStore('counter', {
state: () => ({
count: 0
}),
getters: {
doubleCount: (state) => state.count * 2,
// 使用 this 访问其他 getter
quadrupleCount() {
return this.doubleCount * 2
}
}
})
使用 Getters #
在组件中访问 #
vue
<template>
<div>
<p>Count: {{ counter.count }}</p>
<p>Double: {{ counter.doubleCount }}</p>
<p>Quadruple: {{ counter.quadrupleCount }}</p>
</div>
</template>
<script setup>
import { useCounterStore } from '@/stores/counter'
const counter = useCounterStore()
</script>
解构使用 #
vue
<script setup>
import { storeToRefs } from 'pinia'
import { useCounterStore } from '@/stores/counter'
const counter = useCounterStore()
// 使用 storeToRefs 解构
const { doubleCount, quadrupleCount } = storeToRefs(counter)
</script>
传递参数 #
Getters 本身不接受参数,但可以返回一个函数:
ts
export const useUserStore = defineStore('user', {
state: () => ({
users: [
{ id: 1, name: 'John', age: 25 },
{ id: 2, name: 'Jane', age: 30 },
{ id: 3, name: 'Bob', age: 20 }
]
}),
getters: {
// 返回一个函数
getUserById: (state) => {
return (id: number) => state.users.find(user => user.id === id)
},
// 带多个参数
getUsersByAgeRange: (state) => {
return (min: number, max: number) =>
state.users.filter(user => user.age >= min && user.age <= max)
}
}
})
vue
<template>
<p>{{ userStore.getUserById(1)?.name }}</p>
<p>{{ userStore.getUsersByAgeRange(20, 30).length }} users</p>
</template>
注意事项 #
返回函数的 getter 不会被缓存:
ts
// 每次调用都会重新执行
const user = userStore.getUserById(1) // 执行一次
const user2 = userStore.getUserById(1) // 再次执行
如果需要缓存,可以在组件中使用 computed:
vue
<script setup>
import { computed } from 'vue'
import { useUserStore } from '@/stores/user'
const userStore = useUserStore()
// 缓存结果
const user = computed(() => userStore.getUserById(1))
</script>
访问其他 Store #
ts
export const useCartStore = defineStore('cart', {
state: () => ({
items: [
{ id: 1, productId: 101, quantity: 2 },
{ id: 2, productId: 102, quantity: 1 }
]
}),
getters: {
summary(): string {
const userStore = useUserStore()
return `${userStore.name} 的购物车有 ${this.items.length} 件商品`
}
}
})
TypeScript 类型 #
自动类型推断 #
ts
export const useCounterStore = defineStore('counter', {
state: () => ({
count: 0
}),
getters: {
// 自动推断为 number
doubleCount: (state) => state.count * 2
}
})
显式类型注解 #
ts
export const useUserStore = defineStore('user', {
state: () => ({
users: [] as User[]
}),
getters: {
// 显式指定返回类型
userCount: (state): number => state.users.length,
// 返回可能为 undefined
firstUser: (state): User | undefined => state.users[0],
// 返回函数类型
getUserById: (state): (id: number) => User | undefined => {
return (id) => state.users.find(user => user.id === id)
}
}
})
Setup Store 中的 Getters #
在 Setup Store 中使用 computed:
ts
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
export const useCounterStore = defineStore('counter', () => {
const count = ref(0)
// 使用 computed 定义 getter
const doubleCount = computed(() => count.value * 2)
const quadrupleCount = computed(() => doubleCount.value * 2)
return {
count,
doubleCount,
quadrupleCount
}
})
实际示例 #
购物车 Store #
ts
// stores/cart.ts
import { defineStore } from 'pinia'
interface CartItem {
id: number
productId: number
name: string
price: number
quantity: number
}
export const useCartStore = defineStore('cart', {
state: () => ({
items: [] as CartItem[],
discount: 0
}),
getters: {
// 商品总数
itemCount: (state) =>
state.items.reduce((sum, item) => sum + item.quantity, 0),
// 商品种类数
uniqueItemCount: (state) => state.items.length,
// 小计
subtotal: (state) =>
state.items.reduce((sum, item) => sum + item.price * item.quantity, 0),
// 折扣金额
discountAmount(): number {
return this.subtotal * (this.discount / 100)
},
// 总计
total(): number {
return this.subtotal - this.discountAmount
},
// 是否为空
isEmpty: (state) => state.items.length === 0,
// 获取商品
getItemById: (state) => {
return (productId: number) =>
state.items.find(item => item.productId === productId)
},
// 格式化总价
formattedTotal(): string {
return `¥${this.total.toFixed(2)}`
}
},
actions: {
// ...
}
})
Todo Store #
ts
// stores/todo.ts
import { defineStore } from 'pinia'
interface Todo {
id: number
text: string
completed: boolean
priority: 'low' | 'medium' | 'high'
}
export const useTodoStore = defineStore('todo', {
state: () => ({
todos: [] as Todo[],
filter: 'all' as 'all' | 'active' | 'completed'
}),
getters: {
// 过滤后的 todos
filteredTodos: (state) => {
switch (state.filter) {
case 'active':
return state.todos.filter(todo => !todo.completed)
case 'completed':
return state.todos.filter(todo => todo.completed)
default:
return state.todos
}
},
// 统计数据
totalCount: (state) => state.todos.length,
activeCount: (state) => state.todos.filter(todo => !todo.completed).length,
completedCount: (state) => state.todos.filter(todo => todo.completed).length,
// 完成百分比
completionRate(): number {
if (this.totalCount === 0) return 0
return Math.round((this.completedCount / this.totalCount) * 100)
},
// 按优先级分组
todosByPriority: (state) => {
return {
high: state.todos.filter(todo => todo.priority === 'high'),
medium: state.todos.filter(todo => todo.priority === 'medium'),
low: state.todos.filter(todo => todo.priority === 'low')
}
},
// 是否全部完成
allCompleted: (state) =>
state.todos.length > 0 && state.todos.every(todo => todo.completed),
// 获取 todo
getTodoById: (state) => {
return (id: number) => state.todos.find(todo => todo.id === id)
}
}
})
Getters 最佳实践 #
1. 保持简单 #
ts
// 推荐:简单的计算
getters: {
doubleCount: (state) => state.count * 2
}
// 不推荐:复杂的逻辑(应该放在 action 中)
getters: {
complexCalculation: (state) => {
// 复杂的异步操作或副作用
}
}
2. 利用缓存 #
ts
// 推荐:getter 会自动缓存
getters: {
expensiveCalculation: (state) => {
// 复杂计算,但会被缓存
return state.items.reduce(/* ... */)
}
}
3. 避免副作用 #
ts
// 不推荐:在 getter 中产生副作用
getters: {
badGetter: (state) => {
console.log('side effect') // 副作用
fetch('/api/data') // 异步请求
return state.value
}
}
// 推荐:getter 只做纯计算
getters: {
goodGetter: (state) => {
return state.value * 2
}
}
4. 合理使用参数 #
ts
// 对于需要参数的场景
getters: {
// 返回函数
getItemById: (state) => (id: number) =>
state.items.find(item => item.id === id)
}
// 注意:返回函数的 getter 不会被缓存
下一步 #
现在你已经掌握了 Getters 的使用,接下来让我们学习 Actions。
- Actions方法 - 定义业务逻辑
最后更新:2026-03-28