In state management, Vuex is a very important tool, which helps developers centrally manage the state of applications. The core concepts of Vuex include state, mutations, actions, getters and modules. Today, we will explore one of the key parts: getters, and its related helper function mapGetters. By introducing the principles and implementation of getters in detail, I hope it can help you better understand and use them.
What are Vue Getters?
Getters in Vuex can be considered as computed properties of the store. Just like the computed properties in the Vue component, the return value of getters is cached based on its dependencies and is recalculated only when its dependencies change. This makes getters very suitable for derive some state from state in the store.
Basic use
First, let's look at a simple example:
const store = new ({ state: { todos: [ { id: 1, text: 'Learn Vue', done: true }, { id: 2, text: 'Learn Vuex', done: false } ] }, getters: { doneTodos: state => { return (todo => ) }, doneTodosCount: (state, getters) => { return } } })
In the above code, we define adoneTodos
getter, it returns all completed tasks. At the same time, we also defined adoneTodosCount
The getter, it depends ondoneTodos
, return the number of completed tasks.
Visit Getters
You can passCome to visit getters:
// -> [{ id: 1, text: 'Learn Vue', done: true }] // -> 1
Using Getters in Components
In Vue components, you can usethis.$
Come to visit getters:
computed: { doneTodos () { return this.$ } }
Although this works fine, it will appear a bit verbose for access to multiple getters. To solve this problem, we can usemapGetters
Helper function.
Using mapGetters
mapGetters
is a helper function that helps us map getters in the store to local computed properties. It can greatly simplify the amount of code that uses getters in components.
Basic use
First, we need to import it in the componentmapGetters
:
import { mapGetters } from 'vuex' export default { computed: { ...mapGetters([ 'doneTodos', 'doneTodosCount' ]) } }
Now we can use these computed properties directly in the template:
<template> <div> <p>Done Todos: {{ doneTodos }}</p> <p>Done Todos Count: {{ doneTodosCount }}</p> </div> </template>
Alias
Sometimes, we may want to specify an alias for the map's computed properties. At this time, you can use the object-form parameters:
computed: { ...mapGetters({ completedTasks: 'doneTodos', completedTasksCount: 'doneTodosCount' }) }
This way, we can use alias in the template:
<template> <div> <p>Completed Tasks: {{ completedTasks }}</p> <p>Completed Tasks Count: {{ completedTasksCount }}</p> </div> </template>
The principle and implementation of Getters
To understand more in-depth how getters work, we need to understand the internal implementation of Vuex. Vuex is built on Vue's response system, so the implementation of getters has many similarities with Vue's computed properties.
Create Getters
When we create a store, Vuex will iterate over all the getters we define and create a computed property for each getter. The results of these computed properties are cached and will only be recalculated when their dependencies (i.e. state or other getters) change.
class Store { constructor (options = {}) { // ... const store = this const { getters } = options = {} (getters).forEach(key => { const fn = getters[key] (, key, { get: () => fn(, ) }) }) // ... } }
In the above code we can see that Vuex passA property is defined for each getter, and the getter function of this property will return the calculated result.
Responsive system
Vuex's state is responsive, which means that when we change the data in the state, all getters that depend on this data will be automatically updated. Vuex via VueMethod turns state into a responsive object.
const state = ({ todos: [ { id: 1, text: 'Learn Vue', done: true }, { id: 2, text: 'Learn Vuex', done: false } ] })
In this way, when we change todos in state, all getters that depend on todos (e.g.doneTodos
anddoneTodosCount
) will automatically recalculate and trigger relevant view updates.
Understand mapGetters in depth
mapGetters
It is a very useful helper function provided by Vuex, and its implementation is also relatively simple.mapGetters
The main function is to map getters in the store to computed properties of the component.
Implementation of mapGetters
Let's take a lookmapGetters
Implementation:
export function mapGetters (getters) { const res = {} normalizeMap(getters).forEach(({ key, val }) => { res[key] = function mappedGetter () { return this.$[val] } }) return res }
In the above code,mapGetters
First passnormalizeMap
The function normalizes the passed parameters into an array, then iterates over the array and creates a computed property for each getter. These getter functions that calculate properties will returnthis.$
corresponding value in .
Using normalizeMap
normalizeMap
The function is to normalize the passed parameters (can be arrays or objects) into a standard object array:
function normalizeMap (map) { if (!isValidMap(map)) { return [] } return (map) ? (key => ({ key, val: key })) : (map).map(key => ({ key, val: map[key] })) }
If the passed in is an array,normalizeMap
Each array element will be converted into an object, with the same key and value; if the object is passed in,normalizeMap
Each key-value pair will be converted into an object, and the keys and values correspond to the keys and values of the original object respectively.
The practical application of Getters and mapGetters
In actual projects, getters and mapGetters can help us better organize and manage application status. Let's further understand their practical application through a slightly more complex example.
Example: Todo application
Suppose we are developing a Todo application that needs to showcase all tasks, completed tasks, unfinished tasks, and the number of tasks. We can implement these functions through getters.
First, we define the state and getters of the store:
const store = new ({ state: { todos: [ { id: 1, text: 'Learn Vue', done: true }, { id: 2, text: 'Learn Vuex', done: false }, { id: 3, text: 'Build something awesome', done: false } ] }, getters: { allTodos: state => , doneTodos: state => (todo => ), undoneTodos: state => (todo => !), totalTodosCount: state => , doneTodosCount: (state, getters) => , undoneTodosCount: (state, getters) => } })
Then, use these getters in the component:
import { mapGetters } from 'vuex' export default { computed: { ...mapGetters([ 'allTodos', 'doneTodos', 'undoneTodos', 'totalTodosCount', 'doneTodosCount', 'undoneTodosCount' ]) } }
Show tasks and statistics in templates:
<template> <div> <h1>Todo List</h1> <p>Total Todos: {{ totalTodosCount }}</p> <p>Done Todos: {{ doneTodosCount }}</p> <p>Undone Todos: {{ undoneTodosCount }}</p> <h2>All Todos</h2> <ul> <li v-for="todo in allTodos" :key="">{{ }}</li> </ul> <h2>Done Todos</h2> <ul> <li v-for="todo in doneTodos" :key="">{{ }}</li> </ul> <h2>Undone Todos</h2> <ul> <li v-for="todo in undoneTodos" :key="">{{ }}</li> </ul> </div> </template>
In this way, we can clearly display all tasks, completed and unfinished tasks, and related statistics. Moreover, these data are derived from state through getters, and the view will be automatically updated when the task list in state changes.
Optimization and best practices
In actual development, in addition to using getters and mapGetters correctly, we can also adopt some optimizations and best practices to improve the maintainability and performance of our code.
Avoid unnecessary calculations
Although the results of getters will be cached, you should still be careful to avoid unnecessary calculations when designing getters. For example, if one getter depends on another getter, we should minimize duplicate calculations.
Modular
For large applications, we can split the store into multiple modules, each with its own state, mutations, actions and getters. This makes the code clearer and easier to manage.
const moduleA = { state: () => ({ todos: [] }), getters: { doneTodos: state => (todo => ) }, mutations: { // ... }, actions: { // ... } } const store = new ({ modules: { a: moduleA } })
Use module getters in components:
computed: { ...mapGetters('a', [ 'doneTodos' ]) }
Asynchronous operation
Although getters should not contain asynchronous operations, we can do asynchronous operations in actions and then update state through mutations, triggering the recalculation of getters.
const store = new ({ state: { todos: [] }, getters: { doneTodos: state => (todo => ) }, mutations: { setTodos (state, todos) { = todos } }, actions: { fetchTodos ({ commit }) { // Suppose we have an API call to get todos fetchTodosFromAPI().then(todos => { commit('setTodos', todos) }) } } })
Performance optimization
In applications with high performance requirements, we can use Vuex's plug-in system to optimize the performance of getters. For example, we can write a plugin to cache the results of getters, thus avoiding frequent calculations.
function createGettersCachePlugin () { return store => { const cache = {} ((mutation, state) => { // Clear cache after each mutation (cache).forEach(key => delete cache[key]) }) store._wrappedGetters = (store._wrappedGetters).reduce((wrappedGetters, key) => { const getter = store._wrappedGetters[key] wrappedGetters[key] = (state, getters) => { if (!cache[key]) { cache[key] = getter(state, getters) } return cache[key] } return wrappedGetters }, {}) } } const store = new ({ // ... plugins: [createGettersCachePlugin()] })
This plugin clears the cache after each mutation and caches the results of getters, thus reducing unnecessary calculations.
Summarize
Vuex getters and mapGetters are very powerful tools that help us derive new states from states in the store and use them conveniently in components. In actual development, we can improve the maintainability and performance of our code by using getters and mapGetters rationally. At the same time, we can also adopt some optimizations and best practices to make our applications more robust and efficient.
Hopefully, through the detailed introduction of this article, you can have a deeper understanding of Vuex's getters and mapGetters, and better apply them in real projects. I wish you a happy programming in the world!
This is the end of this article about the principles and usage examples of Vue Getters and mapGetters. For more information about Vue Getters and mapGetters, please search for my previous articles or continue browsing the related articles below. I hope you will support me in the future!