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的響應式設計了。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM