zoukankan      html  css  js  c++  java
  • vuex 源码解析(三) getter属性详解

    有时候我们需要从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的响应式设计了。

  • 相关阅读:
    react-document-title
    react-router
    redux-saga 异步流
    redux
    redux-thunk
    react-router-redux
    [翻译] ClockView 时钟
    [翻译] MZTimerLabel 用作秒表或者倒计时
    [翻译] MCProgressView 使用自定义图片做进度显示
    [翻译] ADPopupView 触摸弹出视窗
  • 原文地址:https://www.cnblogs.com/greatdesert/p/11429856.html
Copyright © 2011-2022 走看看