Sometimes we need to derive some states from the state in the store, such as:
Copy code
<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>
Copy code
If multiple components need to use this property, we can either copy the function or extract it to a shared function and import it in multiple places - either way is not ideal
Vuex allows us to define "getter" (which can be considered as the calculation attribute of store) in the store. Just like the calculation attribute, the return value of getter will be cached according to its dependency, and will be recalculated only when its dependency value changes
The anonymous function corresponding to each getter can take four parameters, which are the state of the current module, getter and the state and getter of the root module, for example:
Copy code
<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>
Copy code
In this way, the property of reverseMessage is implemented in vuex, which is still easy to use. The official website of vuex says that we can use getter as a calculation property. In fact, the internal of vuex also defines getter as a calculated calculation property of vue.
Source code analysis
When creating Vuex.Store() initialization, it will execute installModule() to install the root module. The related getter is as follows:
Copy code
function installModule (store, rootState, path, module, hot) {/ / install module
/ slightly /
module.forEachGetter(function (getter, key) {/ / traverse the getters object of module module. If found, execute the anonymous function parameter 1: each getter value key: corresponding key name
var namespacedType = namespace + key; //Pieced namespace + key name, for example: a/computedCount registerGetter(store, namespacedType, getter, local); //Execute registerGetter in turn
});
/ slightly /
}
Copy code
registerGetter is used to register each getter as follows:
Copy code
function registerGetter (store, type, rawGetter, local) {/ / register getter
If (store. Wrappedgetters [type]) {/ / if there is already a key under store. Wrappedgetters
{ console.error(("[vuex] duplicate getter key: " + type)); //Error is reported, i.e. duplicate is not allowed } return
}
Store. Wrappedgetters [type] = function wrappedgetter (store) {/ / save to the type corresponding to store. Wrappedgetters
return rawGetter( //The four parameters to execute the store function are local state, local getters, root state and root getters local.state, // local state local.getters, // local getters store.state, // root state store.getters // root getters )
};
}
Copy code
In this way, the corresponding getter is stored in the store. It is an anonymous function. One parameter of the function is store, which is the instance of vuex.store(). It will be passed in when the vue instance is created. In this way, the state and getters of the root module can be accessed in the getter
The corresponding wrapped getters are as follows:
Finally, when Vuex goes to resetStoreVM() to create a Vue instance, the logic related to getter is as follows:
Copy code
function resetStoreVM (store, state, hot) {/ / re store data
var oldVm = store._vm; // bind store public getters store.getters = {}; var wrappedGetters = store._wrappedGetters; //Get all getter information of the store, that is, the data saved above. Each value is an anonymous function var computed = {}; //Used to store the last calculated property forEachValue(wrappedGetters, function (fn, key) { //Traverse wrappedGetters // use computed to leverage its lazy-caching mechanism computed[key] = function () { return fn(store); }; //Define computed[key] as a function expression, return the execution result of fn() internally, pass in the store parameter, so that the state and getters of the root module can be accessed in the getter Object.defineProperty(store.getters, key, { //Set the accessor property of the key of store.getters, so that you can access a specific value through store.getters.aaa get: function () { return store._vm[key]; }, enumerable: true // for local getters }); }); /*slightly*/
}
Copy code
After that, if the information in the state is modified, the information in the getter will be updated automatically, thanks to Vue's responsive design.