Vue Getters和mapGetters的原理及使用示例詳解
在Vue.js的狀態(tài)管理中,Vuex是一個(gè)非常重要的工具,它幫助開發(fā)者集中管理應(yīng)用的狀態(tài)。Vuex的核心概念包括state、mutations、actions、getters和modules。今天,我們要深入探討其中一個(gè)關(guān)鍵部分:getters,以及它的相關(guān)輔助函數(shù)mapGetters。通過詳細(xì)介紹getters的原理和實(shí)現(xiàn)過程,希望能幫助你更好地理解和使用它們。
什么是Vue Getters?
Vuex中的getters可以被視為store的計(jì)算屬性。就像Vue組件中的計(jì)算屬性一樣,getters的返回值會(huì)基于其依賴被緩存起來,且只有當(dāng)它的依賴值發(fā)生變化時(shí)才會(huì)重新計(jì)算。這使得getters非常適合用于從store中的state派生出一些狀態(tài)。
基本使用
首先,讓我們看一個(gè)簡(jiǎn)單的例子:
const store = new Vuex.Store({ state: { todos: [ { id: 1, text: 'Learn Vue', done: true }, { id: 2, text: 'Learn Vuex', done: false } ] }, getters: { doneTodos: state => { return state.todos.filter(todo => todo.done) }, doneTodosCount: (state, getters) => { return getters.doneTodos.length } } })
在上面的代碼中,我們定義了一個(gè)doneTodos
的getter,它會(huì)返回所有已完成的任務(wù)。同時(shí),我們還定義了一個(gè)doneTodosCount
的getter,它依賴于doneTodos
,返回已完成任務(wù)的數(shù)量。
訪問Getters
你可以通過store.getters
來訪問getters:
store.getters.doneTodos // -> [{ id: 1, text: 'Learn Vue', done: true }] store.getters.doneTodosCount // -> 1
在組件中使用Getters
在Vue組件中,你可以使用this.$store.getters
來訪問getters:
computed: { doneTodos () { return this.$store.getters.doneTodos } }
這雖然工作正常,但對(duì)于多個(gè)getters的訪問會(huì)顯得有些冗長(zhǎng)。為了解決這個(gè)問題,我們可以使用mapGetters
輔助函數(shù)。
使用mapGetters
mapGetters
是一個(gè)輔助函數(shù),它可以幫助我們將store中的getter映射到局部計(jì)算屬性。它可以極大地簡(jiǎn)化在組件中使用getters的代碼量。
基本使用
首先,我們需要在組件中導(dǎo)入mapGetters
:
import { mapGetters } from 'vuex' export default { computed: { ...mapGetters([ 'doneTodos', 'doneTodosCount' ]) } }
現(xiàn)在,我們可以直接在模板中使用這些計(jì)算屬性:
<template> <div> <p>Done Todos: {{ doneTodos }}</p> <p>Done Todos Count: {{ doneTodosCount }}</p> </div> </template>
別名
有時(shí)候,我們可能想要為映射的計(jì)算屬性指定別名。這時(shí)可以使用對(duì)象形式的參數(shù):
computed: { ...mapGetters({ completedTasks: 'doneTodos', completedTasksCount: 'doneTodosCount' }) }
這樣,我們就可以在模板中使用別名:
<template> <div> <p>Completed Tasks: {{ completedTasks }}</p> <p>Completed Tasks Count: {{ completedTasksCount }}</p> </div> </template>
Getters的原理和實(shí)現(xiàn)
為了更深入地理解getters的工作原理,我們需要了解Vuex的內(nèi)部實(shí)現(xiàn)。Vuex是基于Vue的響應(yīng)系統(tǒng)構(gòu)建的,因此getters的實(shí)現(xiàn)與Vue的計(jì)算屬性有很多相似之處。
創(chuàng)建Getters
當(dāng)我們創(chuàng)建一個(gè)store時(shí),Vuex會(huì)遍歷我們定義的所有g(shù)etters,并為每一個(gè)getter創(chuàng)建一個(gè)計(jì)算屬性。這些計(jì)算屬性的結(jié)果會(huì)被緩存,只有當(dāng)它們的依賴(即state或者其他getters)發(fā)生變化時(shí)才會(huì)重新計(jì)算。
class Store { constructor (options = {}) { // ... const store = this const { getters } = options this.getters = {} Object.keys(getters).forEach(key => { const fn = getters[key] Object.defineProperty(store.getters, key, { get: () => fn(store.state, store.getters) }) }) // ... } }
在上面的代碼中,我們可以看到Vuex通過Object.defineProperty
為每一個(gè)getter定義了一個(gè)屬性,這個(gè)屬性的getter函數(shù)會(huì)返回計(jì)算后的結(jié)果。
響應(yīng)式系統(tǒng)
Vuex的state是響應(yīng)式的,這意味著當(dāng)我們改變state中的數(shù)據(jù)時(shí),所有依賴于這些數(shù)據(jù)的getters都會(huì)自動(dòng)更新。Vuex通過Vue的Vue.observable
方法將state變成響應(yīng)式對(duì)象。
const state = Vue.observable({ todos: [ { id: 1, text: 'Learn Vue', done: true }, { id: 2, text: 'Learn Vuex', done: false } ] })
這樣,當(dāng)我們改變state中的todos時(shí),所有依賴于todos的getters(例如doneTodos
和doneTodosCount
)都會(huì)自動(dòng)重新計(jì)算,并觸發(fā)相關(guān)的視圖更新。
深入理解mapGetters
mapGetters
是Vuex提供的一個(gè)非常有用的輔助函數(shù),它的實(shí)現(xiàn)也相對(duì)簡(jiǎn)單。mapGetters
的主要作用是將store中的getters映射到組件的計(jì)算屬性。
mapGetters的實(shí)現(xiàn)
我們來看看mapGetters
的實(shí)現(xiàn):
export function mapGetters (getters) { const res = {} normalizeMap(getters).forEach(({ key, val }) => { res[key] = function mappedGetter () { return this.$store.getters[val] } }) return res }
在上面的代碼中,mapGetters
首先通過normalizeMap
函數(shù)將傳入的參數(shù)規(guī)范化為一個(gè)數(shù)組,然后遍歷這個(gè)數(shù)組,為每一個(gè)getter創(chuàng)建一個(gè)計(jì)算屬性。這些計(jì)算屬性的getter函數(shù)會(huì)返回this.$store.getters
中的對(duì)應(yīng)值。
使用normalizeMap
normalizeMap
函數(shù)的作用是將傳入的參數(shù)(可以是數(shù)組或?qū)ο螅┮?guī)范化為一個(gè)標(biāo)準(zhǔn)的對(duì)象數(shù)組:
function normalizeMap (map) { if (!isValidMap(map)) { return [] } return Array.isArray(map) ? map.map(key => ({ key, val: key })) : Object.keys(map).map(key => ({ key, val: map[key] })) }
如果傳入的是一個(gè)數(shù)組,normalizeMap
會(huì)將每一個(gè)數(shù)組元素轉(zhuǎn)化為一個(gè)對(duì)象,鍵和值相同;如果傳入的是一個(gè)對(duì)象,normalizeMap
會(huì)將每一個(gè)鍵值對(duì)轉(zhuǎn)化為一個(gè)對(duì)象,鍵和值分別對(duì)應(yīng)原對(duì)象的鍵和值。
Getters和mapGetters的實(shí)際應(yīng)用
在實(shí)際項(xiàng)目中,getters和mapGetters可以幫助我們更好地組織和管理應(yīng)用狀態(tài)。讓我們通過一個(gè)稍微復(fù)雜的例子來進(jìn)一步理解它們的實(shí)際應(yīng)用。
例子:Todo應(yīng)用
假設(shè)我們?cè)陂_發(fā)一個(gè)Todo應(yīng)用,這個(gè)應(yīng)用需要展示所有任務(wù)、已完成任務(wù)、未完成任務(wù)以及任務(wù)的數(shù)量。我們可以通過getters來實(shí)現(xiàn)這些功能。
首先,我們定義store的state和getters:
const store = new Vuex.Store({ 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 => state.todos, doneTodos: state => state.todos.filter(todo => todo.done), undoneTodos: state => state.todos.filter(todo => !todo.done), totalTodosCount: state => state.todos.length, doneTodosCount: (state, getters) => getters.doneTodos.length, undoneTodosCount: (state, getters) => getters.undoneTodos.length } })
然后,在組件中使用這些getters:
import { mapGetters } from 'vuex' export default { computed: { ...mapGetters([ 'allTodos', 'doneTodos', 'undoneTodos', 'totalTodosCount', 'doneTodosCount', 'undoneTodosCount' ]) } }
在模板中展示任務(wù)和統(tǒng)計(jì)信息:
<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="todo.id">{{ todo.text }}</li> </ul> <h2>Done Todos</h2> <ul> <li v-for="todo in doneTodos" :key="todo.id">{{ todo.text }}</li> </ul> <h2>Undone Todos</h2> <ul> <li v-for="todo in undoneTodos" :key="todo.id">{{ todo.text }}</li> </ul> </div> </template>
通過這種方式,我們可以清晰地展示所有任務(wù)、已完成任務(wù)和未完成任務(wù),以及相關(guān)的統(tǒng)計(jì)信息。而且,這些數(shù)據(jù)都是通過getters從state派生出來的,當(dāng)state中的任務(wù)列表發(fā)生變化時(shí),視圖會(huì)自動(dòng)更新。
優(yōu)化和最佳實(shí)踐
在實(shí)際開發(fā)中,除了正確使用getters和mapGetters,我們還可以采取一些優(yōu)化和最佳實(shí)踐來提升代碼的可維護(hù)性和性能。
避免不必要的計(jì)算
雖然getters的結(jié)果會(huì)被緩存,但在設(shè)計(jì)getters時(shí)仍然要注意避免不必要的計(jì)算。例如,如果一個(gè)getter依賴于另一個(gè)getter,我們應(yīng)該盡量減少重復(fù)計(jì)算。
模塊化
對(duì)于大型應(yīng)用,我們可以將store拆分成多個(gè)模塊,每個(gè)模塊都有自己的state、mutations、actions和getters。這樣可以使代碼更清晰,更易于管理。
const moduleA = { state: () => ({ todos: [] }), getters: { doneTodos: state => state.todos.filter(todo => todo.done) }, mutations: { // ... }, actions: { // ... } } const store = new Vuex.Store({ modules: { a: moduleA } })
在組件中使用模塊的getters:
computed: { ...mapGetters('a', [ 'doneTodos' ]) }
異步操作
雖然getters不應(yīng)該包含異步操作,但我們可以在actions中進(jìn)行異步操作,然后通過mutations更新state,從而觸發(fā)getters的重新計(jì)算。
const store = new Vuex.Store({ state: { todos: [] }, getters: { doneTodos: state => state.todos.filter(todo => todo.done) }, mutations: { setTodos (state, todos) { state.todos = todos } }, actions: { fetchTodos ({ commit }) { // 假設(shè)我們有一個(gè)API調(diào)用來獲取todos fetchTodosFromAPI().then(todos => { commit('setTodos', todos) }) } } })
性能優(yōu)化
在高性能需求的應(yīng)用中,我們可以利用Vuex的插件系統(tǒng)來優(yōu)化getters的性能。例如,我們可以編寫一個(gè)插件來對(duì)getters的結(jié)果進(jìn)行緩存,從而避免頻繁的計(jì)算。
function createGettersCachePlugin () { return store => { const cache = {} store.subscribe((mutation, state) => { // 在每次mutation后清除緩存 Object.keys(cache).forEach(key => delete cache[key]) }) store._wrappedGetters = Object.keys(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 Vuex.Store({ // ... plugins: [createGettersCachePlugin()] })
這個(gè)插件在每次mutation后清除緩存,并對(duì)getters的結(jié)果進(jìn)行緩存,從而減少不必要的計(jì)算。
總結(jié)
Vuex的getters和mapGetters是非常強(qiáng)大的工具,它們可以幫助我們從store中的state派生出新的狀態(tài),并在組件中方便地使用這些狀態(tài)。在實(shí)際開發(fā)中,我們可以通過合理使用getters和mapGetters,提高代碼的可維護(hù)性和性能。同時(shí),我們還可以采用一些優(yōu)化和最佳實(shí)踐,使我們的應(yīng)用更加健壯和高效。
希望通過本文的詳細(xì)介紹,你能夠?qū)uex的getters和mapGetters有更深入的理解,并在實(shí)際項(xiàng)目中更好地應(yīng)用它們。祝你在Vue.js的世界中編程愉快!
到此這篇關(guān)于Vue Getters和mapGetters的原理及使用示例詳解的文章就介紹到這了,更多相關(guān)Vue Getters和mapGetters使用內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Vue3使用Vuex之mapState與mapGetters詳解
- 記一次vuex的mapGetters無效原因及解決
- vuex中...mapstate和...mapgetters的區(qū)別及說明
- vue3.0使用mapState,mapGetters和mapActions的方式
- vuex 中輔助函數(shù)mapGetters的基本用法詳解
- vuex2中使用mapGetters/mapActions報(bào)錯(cuò)的解決方法
- vuex中的 mapState,mapGetters,mapActions,mapMutations 的使用
- 詳解vuex中mapState,mapGetters,mapMutations,mapActions的作用
相關(guān)文章
Vue實(shí)現(xiàn)PopupWindow組件詳解
這篇文章主要為大家詳細(xì)介紹了Vue實(shí)現(xiàn)PopupWindow組件,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-04-04vue 解決addRoutes多次添加路由重復(fù)的操作
這篇文章主要介紹了vue 解決addRoutes多次添加路由重復(fù)的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-08-08elementui之封裝下載模板和導(dǎo)入文件組件方式
這篇文章主要介紹了關(guān)于elementui之封裝下載模板和導(dǎo)入文件組件方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-12-12vuejs在解析時(shí)出現(xiàn)閃爍的原因及防止閃爍的方法
這篇文章主要介紹了vuejs在解析時(shí)出現(xiàn)閃爍的原因及防止閃爍的方法,本文介紹的非常詳細(xì),具有參考借鑒價(jià)值,感興趣的朋友一起看看吧2016-09-09自定義Vue中的v-module雙向綁定的實(shí)現(xiàn)
這篇文章主要介紹了自定義Vue中的v-module雙向綁定的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-04-04解決Vue + Echarts 使用markLine標(biāo)線(precision精度問題)
這篇文章主要介紹了解決Vue + Echarts 使用markLine標(biāo)線(precision精度問題),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-07-07vue?perfect-scrollbar(特定框架里使用非該框架定制庫/插件)
這篇文章主要為大家介紹了vue?perfect-scrollbar在特定框架里使用一款并非為該框架定制的庫/插件如何實(shí)現(xiàn),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪<BR>2023-05-05vue3.x?的shallowReactive?與?shallowRef?使用場(chǎng)景分析
在Vue3.x中,`shallowReactive`和`shallowRef`是用于創(chuàng)建淺層響應(yīng)式數(shù)據(jù)的API,它們與`reactive`和`ref`類似,本文介紹vue3.x??shallowReactive?與?shallowRef的使用場(chǎng)景,感興趣的朋友一起看看吧2025-02-02