Vuex源码阅读(二):store内的getters实现逻辑
在Vuex中,getters类似于计算属性(computed),用于派生状态。它们提供了一种便捷的方式来获取经过计算或过滤后的状态数据,并且可以在多个组件之间共享。理解Vuex store内getters的实现逻辑,有助于我们深入掌握Vuex的工作原理,从而更好地在项目中使用它。本文将详细解读Vuex源码中getters的实现逻辑。
目录#
getters的基本概念和使用场景#
基本概念#
getters是Vuex store中的一个对象,它包含了多个函数,这些函数用于根据store中的状态派生新的数据。每个getter函数接收一个state作为第一个参数,还可以接收其他getter函数作为第二个参数。
使用场景#
- 数据过滤:当我们需要从store的状态中过滤出特定的数据时,可以使用getters。例如,从一个包含多个商品的列表中过滤出价格低于某个值的商品。
- 数据计算:对store中的状态进行计算,如计算购物车中商品的总价格。
- 组件间数据共享:多个组件需要使用相同的派生数据时,使用getters可以避免重复的计算逻辑。
Vuex中getters的实现原理概述#
Vuex中的getters实现原理主要基于Object.defineProperty方法来实现数据的劫持和响应式更新。在初始化store时,会对传入的getters对象进行处理,将每个getter函数封装成一个具有缓存功能的只读属性,并将其挂载到store.getters对象上。当组件访问store.getters中的某个属性时,会触发相应的getter函数进行计算。
源码详细解析#
初始化getters#
在Vuex的Store类的构造函数中,有对getters的初始化逻辑。以下是简化后的代码:
class Store {
constructor(options = {}) {
const { getters = {} } = options;
this.getters = {};
const computed = {};
// 遍历getters对象
forEachValue(getters, (fn, key) => {
// 将getter函数封装到computed对象中
computed[key] = () => fn(this.state, this.getters);
// 将getter属性定义到store.getters对象上
Object.defineProperty(this.getters, key, {
get: () => this._vm[key],
enumerable: true
});
});
// 创建一个Vue实例来实现getter的计算属性
this._vm = new Vue({
data: {
$$state: this.state
},
computed
});
}
}
function forEachValue(obj, fn) {
Object.keys(obj).forEach(key => fn(obj[key], key));
}在上述代码中,首先将传入的getters对象复制到一个新的computed对象中,然后使用Object.defineProperty将每个getter属性定义到store.getters对象上。最后,创建一个Vue实例,将computed对象传入其中,利用Vue的计算属性机制来实现getter的缓存和响应式更新。
封装getter函数#
在上面的代码中,将getter函数封装到computed对象中时,传入了this.state和this.getters作为参数。这样,getter函数就可以访问store的状态和其他getter函数。
computed[key] = () => fn(this.state, this.getters);获取getter的值#
当组件访问store.getters中的某个属性时,会触发Object.defineProperty中定义的get方法。
Object.defineProperty(this.getters, key, {
get: () => this._vm[key],
enumerable: true
});这里的this._vm[key]实际上是访问了Vue实例的计算属性,由于Vue的计算属性具有缓存功能,当依赖的状态没有发生变化时,不会重新计算,从而提高了性能。
常见实践和最佳实践#
常见实践#
- 简单数据过滤:在getters中使用数组的过滤方法来过滤状态数据。
const getters = {
filteredProducts: state => state.products.filter(product => product.price < 100)
};- 数据计算:对状态数据进行计算,如计算购物车中商品的总价格。
const getters = {
totalPrice: state => state.cart.reduce((total, item) => total + item.price * item.quantity, 0)
};最佳实践#
- 避免复杂逻辑:getters应该只包含简单的计算逻辑,避免在getters中进行复杂的异步操作或副作用操作。如果需要进行复杂的逻辑处理,可以考虑使用actions。
- 使用命名空间:在大型项目中,为了避免getters的命名冲突,可以使用模块的命名空间。
示例用法#
以下是一个完整的示例,展示如何在Vue项目中使用Vuex的getters。
1. 定义store#
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
const store = new Vuex.Store({
state: {
messages: ['Hello', 'World']
},
getters: {
// 定义一个getter,返回消息的数量
messageCount: state => state.messages.length
}
});
export default store;2. 在组件中使用getters#
<template>
<div>
<p>消息数量: {{ messageCount }}</p>
</div>
</template>
<script>
import { mapGetters } from 'vuex';
export default {
computed: {
...mapGetters(['messageCount'])
}
};
</script>在上述示例中,定义了一个gettermessageCount,用于计算state.messages数组的长度。在组件中使用mapGetters辅助函数来获取getter的值。
总结#
通过对Vuex源码中getters实现逻辑的详细解析,我们了解到getters是基于Vue的计算属性机制实现的,具有缓存和响应式更新的特性。在实际项目中,合理使用getters可以提高代码的可维护性和性能。