Vuex 提供了 mapStatemapGettersmapActionsmapMutations 四个函数,其返回结果分别是 mappedStatemappedGettermappedAction 和 mappedAction 四个函数。

使用方式如下 store/index.js

import { createStore } from 'vuex'const state = {msg: 'hello world'
}const getters = {newMsg: state => `Hi~ ${state.msg}`
}export default createStore({state, getters
})

一、获取 state 中 msg 和 getters 中 newMsg 的方法
1、直接获取

<script setup>import { useStore } from 'vuex'const $store = useStore()console.log($store.state.msg) // 'hello world'console.log($store.getters.newMsg) // 'Hi~ hello world'
</script>

2、计算属性方式获取

<script setup>import { computed } from 'vue'import { useStore } from 'vuex'const $store = useStore()// 计算属性返回的 msg 是一个 ComputedRefImpl 引用对象// 模板以外的地方使用时,需要 ".value"const msg = computed(() => $store.state.msg) console.log(msg.value) // 'hello world'// 计算属性返回的 newMsg 是一个 ComputedRefImpl 引用对象// 模板以外的地方使用时,需要 ".value"const newMsg = computed(() => $store.getters.newMsg) console.log(newMsg.value) // 'Hi~ hello world'
</script>

3、使用 mapState 和 maGetters 方式获取
vue3 组件(选项式风格)

import { useStore, mapState, mapGetters } from 'vuex'
...
setup() {const $store = useStore()// mapState 返回的 msg 是一个 mappedState 函数let { msg } = mapState(['msg']) // 计算属性返回的 msg 是一个 ComputedRefImpl 引用对象msg = computed(msg) console.log(msg.value) // 报错// mapGetters 返回的 newMsg 是一个 mappedGetter 函数let { newMsg } = mapGetters(['newMsg']) // 计算属性返回的 newMsg 是一个 ComputedRefImpl 引用对象newMsg = computed(newMsg) console.log(newMsg.value) // 报错return {msg, newMsg}
}
...

vue3 组件(组合式风格)

<script setup>import { computed } from 'vue'import { useStore, mapState, mapGetters } from 'vuex'const $store = useStore()// mapState 返回的 msg 是一个 mappedState 函数let { msg } = mapState(['msg']) // 计算属性返回的 msg 是一个 ComputedRefImpl 引用对象msg = computed(msg) console.log(msg.value) // 报错// mapGetters 返回的 newMsg 是一个 mappedGetter 函数let { newMsg } = mapGetters(['newMsg']) // 计算属性返回的 newMsg 是一个 ComputedRefImpl 引用对象newMsg = computed(newMsg) console.log(newMsg.value) // 报错
</script>

上述代码在执行的时候,之所以报错,是因为 Vue3 的 computed 函数中没有 this,直接通过 computed 函数去执行 mapState 和 mapGetters 返回的结果 msgnewMsg 以上两个方法会报错,报错内容分别为:

报错! Cannot read properties of undefined (reading 'state') at ReactiveEffect.mappedState [as fn]
报错! Cannot read properties of undefined (reading 'getters') at ReactiveEffect.mappedGetter [as fn]

原因就是因为 Vue3 的 computed 函数里没有 this,导致最后在 "msg.value" 获取值时 mappedState 函数里的 this.$store.state 是在一个 undefined 身上去读取属性,所以报错。mapState 和 mapGetters 的报错原因一致

二、解决方法如下
1、mapState 方式,通过给 mapState 函数返回的结果 mappedState 函数 bind 绑定一个 {$store} 对象,使得其函数内的 this.$store = $store,而不是 undefined,而 $store = userStore(),是一个变量。
注*  {$store} 是 {'$store': $store} 的简写,this.$store === {'$store': $store}.$store === $store

<script setup>import { computed } from 'vue'import { useStore, mapState } from 'vuex'const $store = useStore()// mapState 返回的 msg 是一个 mappedState 函数let { msg } = mapState(['msg']) // 计算属性返回的 msg 是一个 ComputedRefImpl 引用对象msg = computed(msg.bind({$store}))console.log(msg.value) // 'hello world'
</script>

2、magGetters

<script setup>import { computed } from 'vue'import { useStore, mapGetters } from 'vuex'const $store = useStore()// mapGetters 返回的 newMsg 是一个 mappedGetter 函数let { newMsg } = mapGetters (['newMsg']) // 计算属性返回的 newMsg 是一个 ComputedRefImpl 引用对象newMsg = computed(newMsg.bind({$store}))console.log(newMsg.value) // 'Hi~ hello world'
</script>

但是每次使用 mapState 和 mapGetters 都要去绑定一个 store 对象,这很不方便,所以,自己改造封装一个 mapState 和 mapGetters,名字改成大写的 MAPSTAGE 和 MAPGETTERS。

开始封装,准备一个脚本文件
store/mapStoreReset.js,除了全局模式,还兼容 modules 模块的获取方式。

import { computed } from 'vue'
import { useStore, mapState, mapGetters } from 'vuex'
// mapActions, mapMutations 组件中可以直接使用原生写法,不需要封装/*** 重新封装 mapState,使用方法与返回结果跟官方原生 mapState 一致,适用全局和 modules 局部* 推荐使用数组形式获取,写法更简洁*/
const MAPSTATE = (...args) => {const $store = useStore()const methodName = 'MAPSTATE'const target = 'state'let modulesName = nulllet params = nulllet storeState = {}// 检测参数在 state 中是否存在const paramsCheckFn = (paramsValusArgs, $storeState) => {paramsValusArgs.forEach(item => {if (!Object.keys($storeState).includes(item)) {throw new Error(`${methodName}方法里的参数"${item}" Vuex ${target} 中不存在`)}})}// 调用 mapState 的参数为对象const useObjectTypeFn = (params, $storeState) => {if (Object.prototype.toString.call(params) === '[object Object]') {const paramsValusArgs = Object.values(params)paramsCheckFn(paramsValusArgs, $storeState)}}// 调用 mapState 的参数为数组const useArrayTypeFn = (params, $storeState) => {if (Array.isArray(params)) {if (!params.length) throw new Error('${methodName}方法的数组参数长度不能为0')paramsCheckFn(params, $storeState)}}// computed 优化,给 mapState 返回的每个函数的 this 绑定 {$store} 对象const improveComputedFn = storeStateFnsObj => {Object.keys(storeStateFnsObj).forEach(key => {const fn = storeStateFnsObj[key].bind({$store})storeState[key] = computed(fn)})}if (args && args.length === 1) {// 用户调用全局 Vuexparams = args[0]useObjectTypeFn(params, $store.state)useArrayTypeFn(params, $store.state)improveComputedFn(mapState(params))} else if (args && args.length === 2) {// 用户调用局部模块化 VuexmodulesName = args[0]params = args[1]useObjectTypeFn(params, $store.state[modulesName])useArrayTypeFn(params, $store.state[modulesName])improveComputedFn(mapState(modulesName, params))}return storeState
}/*** 重新封装 mapGetters,使用方法与返回结果跟官方原生 mapGetters 一致,适用全局和 modules 局部* 推荐使用数组形式获取,写法更简洁*/
const MAPGETTERS = (...args) => {const $store = useStore()const methodName = 'MAPGETTERS'const target = 'getters'let modulesName = nulllet params = nullconst storeGetters = {}// 检测参数在 getters 中是否存在const paramsCheckFn = (paramsValusArgs, isModulesName) => {// 检测参数在 getters 中是否存在paramsValusArgs.forEach(item => {if (isModulesName) {item =  `${modulesName}/${item}`} if (!Object.keys($store.getters).includes(item)) {throw new Error(`${methodName}方法里的参数"${item}" Vuex ${target} 中不存在`)}})}// 调用 mapGetters 的参数为对象const useObjectTypeFn = (params, modulesName) => {if (Object.prototype.toString.call(params) === '[object Object]') {const paramsValusArgs = Object.values(params)paramsCheckFn(paramsValusArgs, modulesName)}}// 调用 mapGetters 的参数为数组const useArrayTypeFn = (params, modulesName) => {if (Array.isArray(params)) {if (!params.length) throw new Error('${methodName}方法的数组参数长度不能为0')paramsCheckFn(params, modulesName)}}// computed 优化,给 mapGetters 返回的每个函数的 this 绑定 {$store} 对象const improveComputedFn = storeGettersFnsObj => {Object.keys(storeGettersFnsObj).forEach(key => {const fn = storeGettersFnsObj[key].bind({$store})storeGetters[key] = computed(fn)})}if (args && args.length === 1) {// 用户调用全局 Vuexparams = args[0]useObjectTypeFn(params)useArrayTypeFn(params)improveComputedFn(mapGetters(params))} else if (args && args.length === 2) {// 用户调用局部模块化 VuexmodulesName = args[0]params = args[1]useObjectTypeFn(params, modulesName)useArrayTypeFn(params, modulesName)improveComputedFn(mapGetters(modulesName, params))}return storeGetters
}export { MAPSTATE, MAPGETTERS }

封装完成,现在来个例子,往下看。

新建一个模块文件 store/modules/hobby.js

export default {namespaced: true, // 模块化时必须要将这个属性设置为 truestate = {hobby: '不抽烟',plan: '不喝酒',like: '不烫头'},getters: {totalHobby: state => `2023 流行 ${state.hobby}-${state.plan}-${state.like}`}
}

在最新的 store/index.js 文件中引入上面的 modules 模块文件 hobby.js。

import { createStore } from 'vuex'
import hobby from './modules/hobby' // 导入文件
const state = {msg: 'hello world'
}const getters = {newMsg: state => `Hi~ ${state.msg}`
}const modules = {hobby // 在模块中使用
}export default createStore({state, getters, modules
})

Vue 组件使用

<script setup>// 导入封装好的方法import { MAPSTATE, MAPGETTERS } from '@/store/mapStoreReset'// 获取 state 数据// 使用方式1 :对象形式const { msg } = MAPSTATE({msg: 'msg'})// 使用方式2 :数组形式const { msg } = MAPSTATE(['msg'])// 以上两种方式获取的是全局的 state 对象里的数据,结果为 // msg = 'hello world'// 使用方式3 :对象形式-获取 modules 模块里的 hobby.js 的 state 数据const { hobby, plan, like } = MAPSTATE('hobby', {hobby: 'hobby', plan: 'plan', like: 'like'})// 使用方式4 :数组形式-获取 modules 模块里的 hobby.js 的 state 数据const { hobby, plan, like } = MAPSTATE('hobby', ['hobby', 'plan', 'like'])// 以上两种方式获取的是 hobby.js 模块(局部)的 state 对象里的数据,结果为 // bobby = '不抽烟' , plan = '不喝酒' , like = '不烫头'  // 获取 getters 数据// 获取方式1:对象形式const { newMsg } = MAPGETTERS({newMsg: 'newMsg'})// 获取方式2:数组形式const { newMsg } = MAPGETTERS({['newMsg'])// 以上两种方式获取的是全局的 getters 对象里的数据,结果为 // newMsg = 'Hi~ hello world'// 获取方式3:对象形式-获取 hobby.js 模块里的 getters 数据const { totalHobby } = MAPGETTERS('hobby', {totalHobby: 'totalHobby'})// 获取方式4:数组形式-获取 hobby.js 模块里的 getters 数据const { totalHobby } = MAPGETTERS({'hobby', ['totalHobby'])// 以上两种方式获取的是全局的 getters 对象里的数据,结果为 // 20223 流行 不抽烟-不喝酒-不烫头
</script>

本文属个人观点,纯手打,如有错误,欢迎指正,谢谢,完!

Vue3 直接使用Vuex的mapState和mapGetters时报错的分析及解决方案相关推荐

  1. vue3.0下如何使用mapState,mapGetters和mapActions

    vue3.0下如何使用mapState,mapGetters和mapActions 1.新建useMapper.js 2.新建useState.js 3.新建useGetters.js 4.新建use ...

  2. Vuex实践-mapState和mapGetters

    一.前言 本文章是vuex系列的最后一篇,主要总结的是如何使用mapState和mapGetters访问vuex中的state和getters. 二.多个模块中mapState和mapGetters的 ...

  3. vuex进阶 mapState、mapGetters、mapMutations、mapActions

    一.state 1.1 引入vuex 以后,我们需要在state中定义变量,类似于vue中的data,通过state来存放状态 import Vue from 'vue' import Vuex fr ...

  4. vuex的mapState,mapGetters,mapActions,mapMutations与模块化

    mapState 和mapGetters 用于生成计算属性computed mapState({"计算属性名":"State数据","xxx" ...

  5. [vue3+ts]方法一:使用vuex的mapState和mapGetters

    src下新建hooks/useState.js import { computed } from 'vue' import { mapState, useStore } from 'vuex' // ...

  6. Vuex中mapState和mapGetters的区别

    ...mapState辅助函数 当一个组件需要获取多个状态的时候,将这些状态都声明为计算属性会有些重复和冗余.为了解决这个问题,我们可以使用...mapState辅助函数帮助我们生成计算属性,当映射的 ...

  7. vuex:弄懂mapState、mapGetters、mapMutations、mapActions

    转载地址:https://zhuanlan.zhihu.com/p/100941659 vuex进阶 一.state 1.1 引入vuex 以后,我们需要在state中定义变量,类似于vue中的dat ...

  8. VUE学习(二十一)、Vuex(getters、mapState与mapGetters、mapMutations与mapActions、多组件共享数据、模块化编码)

    VUE学习(二十一).Vuex(getters.mapState与mapGetters.mapMutations与mapActions.多组件共享数据.模块化编码) 一.Vuex普通实现求和案例 演示 ...

  9. vuex的辅助函数:mapState和mapGetters

    文章目录 自己写计算属性 mapState/mapGetters生成计算属性 数组写法 对象写法 对象写法(key-value,value是一个字符串) 对象写法(key-value,value是一个 ...

最新文章

  1. Android快速开发系列 10个常用工具类
  2. 让使用SQLite的.NET应用自适应32位/64位系统
  3. LeetCode—207. 课程表
  4. java中对象作为参数_java中对象引用,特别作为参数时候注意事项
  5. 同步助手iphone4_88 元淘来的 iPhone 4 降级到 iOS 6,甚至还能跑 “大型游戏”
  6. matex2推送鸿蒙系统,拜拜了,Powered by Android!
  7. WebRTC下载及编译(二)
  8. 不同平台安装python的方式一样吗_Python软件的正确安装方式
  9. Linux网络抓包工具tcpdump
  10. 高校学籍管理系统(SQL Server数据库课程设计)
  11. 思维导图编辑最常用的几种Edraw Max(亿图)快捷键
  12. C#解决串口数据丢失问题
  13. 深入理解java虚拟机(zz)
  14. python 调用scp命令 实践
  15. 20-《电子入门趣谈》第四章_自己制作电路板-4.1面包板的介绍和经典案例使用教程
  16. 云计算入门必备的60条术语
  17. [Windows实用软件推荐:1]本地搜索工具Everything
  18. 徐无忌深入浅出网络笔记:什么是OSI七层网络模型
  19. 啊哈 算法 Java_《啊哈!算法》.啊哈磊.高清版.pdf
  20. C文件中的中文乱码 notepad2

热门文章

  1. 35岁前要上的33堂理财课
  2. python随机数random.sample
  3. MetaRim这个项目怎么样?机甲激战为何称为链游崛起之星
  4. 设计模式----原型模式
  5. python 面向对象之封装与类与对象
  6. 基于jsp(java)高校智能排课系统设计
  7. springboot+高校教室排课系统 毕业设计-附源码221556
  8. Like 运算符中出错: 字符串模式“%XXXX*XXXX%”无效
  9. 网络安全学习篇26_阶段一小结篇_kali中间人渗透
  10. Windows 10设置指纹(Windows Hello)弹窗闪退修复