有时候我们需要从store中的state中派生出一些状态,例如:

  1. <div id="app">
  2. <p>{{reverseMessage}}</p>
  3. </div>
  4. <script>
  5. const store = new Vuex.Store({
  6. state:{reverseMessage:'Hello Vue!'}
  7. })
  8. new Vue({
  9. el:'#app',
  10. store,
  11. computed:{
  12. reverseMessage:function(){return this.$store.state.reverseMessage.split('').reverse().join('')}
  13. }
  14. })
  15. </script>

如果多个组件需要用到此属性,我们要么复制这个函数,或者抽取到一个共享函数然后在多处导入它---无论哪种方式都不是很理想

writer by:大沙漠 QQ:22969969

Vuex允许我们在store中定义"getter"(可以认为是store的计算属性),就像计算属性一样,getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算

每个getter对应的匿名函数可以带四个参数,分别是当前模块的state、getter和根模块的state、getter,例如:

  1. <div id="app">
  2. <p>{{reverseMessage}}</p>
  3. </div>
  4. <script>
  5. const store = new Vuex.Store({
  6. state:{reverseMessage:'Hello Vue!'},
  7. getters:{
  8. reverseMessage:function(state){return state.reverseMessage.split('').reverse().join('');}
  9. }
  10. })
  11. new Vue({
  12. el:'#app',
  13. store,
  14. computed:{
  15. reverseMessage:function(){return this.$store.getters.reverseMessage}
  16. }
  17. })
  18. </script>

这样在vuex内部就把reverseMessage这个属性给实现了,还是很好用的,vuex官网里说我们可以把getter当作计算属性一样来使用,事实上vuex内部也是把getter定义为vue的computed计算属性来实现的。

源码分析


在创建Vuex.Store()初始化时会执行installModule()安装根模块,和getter相关的如下:

  1. function installModule (store, rootState, path, module, hot) { //安装模块
  2. /*略*/
  3. module.forEachGetter(function (getter, key) { //遍历module模块的getters对象,如果找到了,则执行这个匿名函数 参数1:每个getter值 key:对应的键名
  4. var namespacedType = namespace + key; //拼凑命名空间+键名,例如:a/computedCount
  5. registerGetter(store, namespacedType, getter, local); //依次执行registerGetter
  6. });
  7.  
  8. /*略*/
  9. }

registerGetter用于注册每个getter,如下:

  1. function registerGetter (store, type, rawGetter, local) { //注册getter
  2. if (store._wrappedGetters[type]) { //如果store._wrappedGetters下已经有key了
  3. {
  4. console.error(("[vuex] duplicate getter key: " + type)); //则报错,即不允许重复
  5. }
  6. return
  7. }
  8. store._wrappedGetters[type] = function wrappedGetter (store) { //保存到store._wrappedGetters对应的type里
  9. return rawGetter( //执行store函数 四个参数分别为local state、local getters、root state、root getters
  10. local.state, // local state
  11. local.getters, // local getters
  12. store.state, // root state
  13. store.getters // root getters
  14. )
  15. };
  16. }

这样在 store._wrappedGetters中就存储了对应的getter了,是一个匿名函数,函数有一个参数是store,这个是vuex.store()的实例,一会创建vue实例时会传入的,这样在geter里就能访问到根模块的state和getters了

例子执行到这里对应的_wrappedGetters如下:

最后Vuex走到resetStoreVM()去创建一个Vue实例时,和getter有关的逻辑如下:

  1. function resetStoreVM (store, state, hot) { //重新存储数据
  2. var oldVm = store._vm;
  3.  
  4. // bind store public getters
  5. store.getters = {};
  6. var wrappedGetters = store._wrappedGetters; //获取store的所有getter信息,也就是上面保存的数据,每个值是一个匿名函数
  7. var computed = {}; //用于存储最后的计算属性
  8. forEachValue(wrappedGetters, function (fn, key) { //遍历wrappedGetters
  9. // use computed to leverage its lazy-caching mechanism
  10. computed[key] = function () { return fn(store); }; //将computed[key]定义为一个函数表达式,内部返回fn()执行后的结果,传入store参数,这样在geter里就能访问到根模块的state和getters了
  11. Object.defineProperty(store.getters, key, { //设置store.getters的key的访问器属性,这样就可以通过store.getters.aaa访问到某个具体的值了
  12. get: function () { return store._vm[key]; },
  13. enumerable: true // for local getters
  14. });
  15. });
  16.  
  17. /*略*/
  18. }

之后如果有修改了state里的信息,getter里的信息都会自动更新的,这个归功于Vue的响应式设计了。

vuex 源码解析(三) getter属性详解的更多相关文章

  1. jQuery 源码解析(三) pushStack方法 详解

    该函数用于创建一个新的jQuery对象,然后将一个DOM元素集合加入到jQuery栈中,最后返回该jQuery对象,有三个参数,如下: elems Array类型 将要压入 jQuery 栈的数组元素 ...

  2. guava-retrying 源码解析(停止策略详解)

    一.停止策略相关类 1.停止策略接口:StopStrategy接口,只有一个抽象方法 // 是否应该停止重试.不同的停止策略有不同的实现.boolean shouldStop(Attempt fail ...

  3. guava-retrying 源码解析(等待策略详解)

    一.等待策略相关类: 1.等待策略接口:WaitStrategy接口 该接口只有一个方法,就是返回尝试失败之后,下一次尝试之前的等待时间.long computeSleepTime(Attempt f ...

  4. guava-retrying 源码解析(阻塞策略详解)

    这是一种策略,用于决定重试者应如何在重试尝试之间进行阻止.通常这只是一个thread.sleep(),但是如果需要的话,实现可能更复杂. 一.阻塞策略相关的类或接口 1.阻塞策略接口:BlockStr ...

  5. Celery 源码解析三: Task 对象的实现

    Task 的实现在 Celery 中你会发现有两处,一处位于 celery/app/task.py,这是第一个:第二个位于 celery/task/base.py 中,这是第二个.他们之间是有关系的, ...

  6. Mybatis源码解析(三) —— Mapper代理类的生成

    Mybatis源码解析(三) -- Mapper代理类的生成   在本系列第一篇文章已经讲述过在Mybatis-Spring项目中,是通过 MapperFactoryBean 的 getObject( ...

  7. ReactiveCocoa源码解析(三) Signal代码的基本实现

    上篇博客我们详细的聊了ReactiveSwift源码中的Bag容器,详情请参见<ReactiveSwift源码解析之Bag容器>.本篇博客我们就来聊一下信号量,也就是Signal的的几种状 ...

  8. ReactiveSwift源码解析(三) Signal代码的基本实现

    上篇博客我们详细的聊了ReactiveSwift源码中的Bag容器,详情请参见<ReactiveSwift源码解析之Bag容器>.本篇博客我们就来聊一下信号量,也就是Signal的的几种状 ...

  9. React的React.createRef()/forwardRef()源码解析(三)

    1.refs三种使用用法 1.字符串 1.1 dom节点上使用 获取真实的dom节点 //使用步骤: 1. <input ref="stringRef" /> 2. t ...

随机推荐

  1. 【分布式存储】Glusterfs快速搭建

    目录 环境准备 步骤1,保证至少有三台服务器 步骤2,格式化和配置硬盘 步骤3,安装GlusterFS 步骤4,配置防火墙 步骤5,配置 trusted pool 步骤6,设置GlusterFS卷 步 ...

  2. node.js中this指向失效解决

    问题:在外部单独使用类实例对象的方法,this没有指向该类实例对象 代码如下 class CQH { hello() { let name = this.name(); console.log(`He ...

  3. 基于C# WinForms窗体——飞机大战

    原文:基于C# WinForms窗体——飞机大战 using System; using System.Collections.Generic; using System.ComponentModel ...

  4. python3的reload(sys)

    import sys reload(sys) sys.setdefaultencoding(‘utf-8’) 以上是python2的写法,但是在python3中这个需要已经不存在了,这么做也不会什么实 ...

  5. (一)创建新的react native 应用程序

    最近开始学习ReactNative了,首先了解下ReactNative http://wiki.jikexueyuan.com/project/react-native/GettingStarted. ...

  6. Android,百度,云知声tts总结

    最近在做Android语音播报功能(TTS),现总结如下:(ps:demo代码地址:https://github.com/giserlong/TTS_DEMO) 一.Android原生接口 用Andr ...

  7. SQL学习_SQL函数

    常用的 SQL 函数 1. 算术函数 SELECT ABS(-2),运行结果为 2 SELECT MOD(101,3),运行结果 2 SELECT ROUND(37.25,1),运行结果 37.3 2 ...

  8. springboot整合spring Data JPA

    今天敲代码,一连串的错误,我也是服气~果然,我们不是在出bug,就是在找bug的路上…… 今天完成的是springboot整合spring data JPA ,出了一连串的错,真是头大 java.sq ...

  9. SRDC - ORA-1628: Checklist of Evidence to Supply (Doc ID 1682729.1)

    SRDC - ORA-1628: Checklist of Evidence to Supply (Doc ID 1682729.1) Action Plan 1. Execute srdc_db_u ...

  10. sleep() 和 wait() 有什么区别:

      ①原理不同. ​ sleep()方法是Thread类的静态方法,是线程用来控制自身流程的,它会使此线程暂停执行一段时间,而把执行机会让给其他线程,等到计时时间一到,此线程会自动苏醒.而wait() ...