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