vuex 源码解析(三) getter属性详解
程序员文章站
2022-07-09 20:46:31
有时候我们需要从store中的state中派生出一些状态,例如: 如果多个组件需要用到此属性,我们要么复制这个函数,或者抽取到一个共享函数然后在多处导入它 无论哪种方式都不是很理想 writer by:大沙漠 QQ:22969969 Vuex允许我们在store中定义"getter"(可以认为是st ......
有时候我们需要从store中的state中派生出一些状态,例如:
<div id="app"> <p>{{reversemessage}}</p> </div> <script> const store = new vuex.store({ state:{reversemessage:'hello vue!'} }) new vue({ el:'#app', store, computed:{ reversemessage:function(){return this.$store.state.reversemessage.split('').reverse().join('')} } }) </script>
如果多个组件需要用到此属性,我们要么复制这个函数,或者抽取到一个共享函数然后在多处导入它---无论哪种方式都不是很理想
writer by:大沙漠 qq:22969969
vuex允许我们在store中定义"getter"(可以认为是store的计算属性),就像计算属性一样,getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算
每个getter对应的匿名函数可以带四个参数,分别是当前模块的state、getter和根模块的state、getter,例如:
<div id="app"> <p>{{reversemessage}}</p> </div> <script> const store = new vuex.store({ state:{reversemessage:'hello vue!'}, getters:{ reversemessage:function(state){return state.reversemessage.split('').reverse().join('');} } }) new vue({ el:'#app', store, computed:{ reversemessage:function(){return this.$store.getters.reversemessage} } }) </script>
这样在vuex内部就把reversemessage这个属性给实现了,还是很好用的,vuex官网里说我们可以把getter当作计算属性一样来使用,事实上vuex内部也是把getter定义为vue的computed计算属性来实现的。
源码分析
在创建vuex.store()初始化时会执行installmodule()安装根模块,和getter相关的如下:
function installmodule (store, rootstate, path, module, hot) { //安装模块 /*略*/ module.foreachgetter(function (getter, key) { //遍历module模块的getters对象,如果找到了,则执行这个匿名函数 参数1:每个getter值 key:对应的键名 var namespacedtype = namespace + key; //拼凑命名空间+键名,例如:a/computedcount registergetter(store, namespacedtype, getter, local); //依次执行registergetter }); /*略*/ }
registergetter用于注册每个getter,如下:
function registergetter (store, type, rawgetter, local) { //注册getter if (store._wrappedgetters[type]) { //如果store._wrappedgetters下已经有key了 { console.error(("[vuex] duplicate getter key: " + type)); //则报错,即不允许重复 } return } store._wrappedgetters[type] = function wrappedgetter (store) { //保存到store._wrappedgetters对应的type里 return rawgetter( //执行store函数 四个参数分别为local state、local getters、root state、root getters local.state, // local state local.getters, // local getters store.state, // root state store.getters // root getters ) }; }
这样在 store._wrappedgetters中就存储了对应的getter了,是一个匿名函数,函数有一个参数是store,这个是vuex.store()的实例,一会创建vue实例时会传入的,这样在geter里就能访问到根模块的state和getters了
例子执行到这里对应的_wrappedgetters如下:
最后vuex走到resetstorevm()去创建一个vue实例时,和getter有关的逻辑如下:
function resetstorevm (store, state, hot) { //重新存储数据 var oldvm = store._vm; // bind store public getters store.getters = {}; var wrappedgetters = store._wrappedgetters; //获取store的所有getter信息,也就是上面保存的数据,每个值是一个匿名函数 var computed = {}; //用于存储最后的计算属性 foreachvalue(wrappedgetters, function (fn, key) { //遍历wrappedgetters // use computed to leverage its lazy-caching mechanism computed[key] = function () { return fn(store); }; //将computed[key]定义为一个函数表达式,内部返回fn()执行后的结果,传入store参数,这样在geter里就能访问到根模块的state和getters了 object.defineproperty(store.getters, key, { //设置store.getters的key的访问器属性,这样就可以通过store.getters.aaa访问到某个具体的值了 get: function () { return store._vm[key]; }, enumerable: true // for local getters }); }); /*略*/ }
之后如果有修改了state里的信息,getter里的信息都会自动更新的,这个归功于vue的响应式设计了。