vue3.0使用mapState,mapGetters和mapActions的方式
作者:一个写前端的 发布时间:2023-07-02 16:49:56
标签:vue3,mapState,mapGetters,mapActions
vue2.0中使用mapState及mapActions的方式
// 使用mapState
computed: {
...mapState({
//...
})
}
methods: {
...mapActions(['fnA', 'fnB'])
}
vue3.0中获取state和使用actions的方式
import {computed} from 'vue'
import {useStore} from 'vuex'
setup() {
const store = useStore();
const stateA = computed(() => store.state.stateA);
const stateB = computed(() => store.state.stateB);
const methodA = store.dispatch('methodA', {name: '张三'});
}
如何才能在vue3下使用mapState这些api呢?
答案是封装mapState,mapGetters,mapActions方法。
1、新建useMapper.js
import { useStore } from 'vuex'
import { computed } from 'vue'
export function useStateMapper(mapper, mapFn) {
const store = useStore();
const storeStateFns = mapFn(mapper);
const storeState = {};
Object.keys(storeStateFns).forEach(fnKey => {
// vuex源码中mapState和mapGetters的方法中使用的是this.$store,所以更改this绑定
const fn = storeStateFns[fnKey].bind({ $store: store });
storeState[fnKey] = computed(fn)
})
return storeState
}
export function useActionMapper(mapper, mapFn) {
const store = useStore();
const storeActionsFns = mapFn(mapper);
const storeAction = {};
Object.keys(storeActionsFns).forEach(fnKey => {
storeAction[fnKey] = storeActionsFns[fnKey].bind({ $store: store })
})
return storeAction
}
2、新建useState.js
import { mapState, createNamespacedHelpers } from 'vuex'
import { useStateMapper } from './useMapper'
import {checkType} from './index'
/**
*
* @param {*} moduleName 模块名称
* @param {*} mapper state属性集合 ['name', 'age']
* @returns
*/
export function useState(moduleName, mapper) {
let mapperFn = mapState;
// 如果使用模块化,则使用vuex提供的createNamespacedHelpers方法找到对应模块的mapState方法
if (checkType(moduleName) === "[object String]" && moduleName.length > 0) {
mapperFn = createNamespacedHelpers(moduleName).mapState
}
return useStateMapper(mapper, mapperFn)
}
3、新建useGetters.js
import { mapGetters, createNamespacedHelpers } from 'vuex'
import { useStateMapper } from './useMapper'
import {checkType} from './index'
/**
*
* @param {*} moduleName 模块名称
* @param {*} mapper getters属性集合 ['name', 'age']
* @returns
*/
export function useGetters(moduleName, mapper) {
let mapperFn = mapGetters;
// 如果使用模块化,则使用vuex提供的createNamespacedHelpers方法找到对应模块的mapGetters方法
if (checkType(moduleName) === "[object String]" && moduleName.length > 0) {
mapperFn = createNamespacedHelpers(moduleName).mapGetters
}
return useStateMapper(mapper, mapperFn)
}
4、新建useActions.js
import { mapActions, createNamespacedHelpers } from 'vuex';
import {useActionMapper} from './useMapper'
import {checkType} from './index'
/**
*
* @param {*} moduleName 模块名称
* @param {*} mapper 方法名集合 ['fn1', 'fn2']
* @returns
*/
export function useActions(moduleName, mapper) {
let mapperFn = mapActions;
// 如果使用模块化,则使用vuex提供的createNamespacedHelpers方法找到对应模块的mapActions方法
if (checkType(moduleName) === "[object String]" && moduleName.length > 0) {
mapperFn = createNamespacedHelpers(moduleName).mapActions
}
return useActionMapper(mapper, mapperFn)
}
5、页面中使用
<template>
<div class="home">
<span>姓名:{{name}} 年龄:{{age}} 性别:{{sex}}</span>
<button @click="changeName">改名</button>
</div>
</template>
<script>
// @ is an alias to /src
import {useState} from '@/utils/useState'
import {useActions} from '@/utils/useAction'
export default {
name: "home",
setup() {
const storeState = useState('home', ['name', 'age', 'sex'])
const storeActions = useActions('home', ['setName'])
const changeName = () => {
storeAction.setName('李四')
}
return {
changeName,
...storeState,
...storeActions
};
},
};
</script>
vue3对vuex中mapState,mapGetters辅助函数封装
1. readonly API的使用
在我们传递给其他组件数据时,如果直接将响应式数据传递给子组件。子组件如果使用数据不规范,修改了父组件传进来的props值没有任何反馈。
// 父组件
// <ReadonlyChild :info="info" />
setup() {
const info = reactive({
name: "哇哈哈",
});
return {
info,
};
}
// 子组件
setup(props) {
const onChangeInfo = () => {
const info = props.info;
// 修改父组件传来的props 没有任何反馈。
info.name = "woowow";
};
return {
onChangeInfo,
};
}
开发中我们往往希望其他组件使用我们传递的内容,但是不允许它们修改时,就可以使用 readonly了。
// 父组件
// <ReadonlyChild :info="infoReadonly" />
setup() {
const info = reactive({
name: "哇哈哈",
});
const infoReadonly = readonly(info);
const onChangeInfo = () => {
// 在父组件中可修改info中的值,子组件依然可响应更新
info.name = "父组件给你的值";
};
return {
infoReadonly,
onChangeInfo
};
}
// 子组件
setup(props) {
const onChangeInfo = () => {
const info = props.info;
// 此时修改props时,控制台会有一个警告:
// Set operation on key "name" failed: target is readonly.
info.name = "woowow";
};
return {
onChangeInfo,
};
}
2. 响应式变量直接解构会失去响应性
将响应式变量直接解构会失去其响应性
const info = reactive({ age: 18 });
// 直接解构后 age 值失去响应性,当 onChangeAge 函数触发时,age值不在变,而ageRef 依然具有响应性
const { age } = info;
const { age: ageRef } = toRefs(info);
const onChangeAge = () => {
info.age++;
};
3. watchEffect 清除副作用
watchEffect API 可自动收集依赖项,当依赖项改变时触发 * 函数。当我们在 * 函数执行额外的副作用函数,例如:发送网络请求时。每当依赖性项变更都会发起一个新的网络请求,那么上一次的网络请求应该被取消掉。这个时候我们就可以清除上一次的副作用了。
setup() {
const count = ref(0);
const onChangeCount = () => {
count.value++;
};
watchEffect((onInvalidate) => {
// * 函数中需要发起网络请求,用setTimeout模拟
const timer = setTimeout(() => {
console.log("请求成功啦");
}, 2000);
// 在 * 函数重新执行时触发onInvalidate函数
onInvalidate(() => {
// 在这个函数中清除请求
clearTimeout(timer);
console.log("onInvalidate 回调触发");
});
// 自动收集count的依赖
console.log("count-在改变", count.value);
});
return {
count,
onChangeCount,
};
}
4. setup 函数访问Vuex中Store数据
4.1 使用mapState辅助函数
通常需要通computed函数来获取state中数据,并保存响应性。
setup() {
const store = useStore();
// 在setup中要获取store中的state。如果state非常多,无疑这样做很繁琐
const uName = computed(() => store.state.name);
const uAge = computed(() => store.state.age);
const uHeight = computed(() => store.state.height);
/**
* 直接使用mapState辅助函数得不到想要的结果
* 这样获取的storeState 是一个 { name: function mappedState (){...}, age: function mappedState (){...}, height: function mappedState (){...} } 这样的对象
*/
const storeState = mapState(["name", "age", "height"]);
// 需要对返回值进行处理
const resStoreState = {};
Object.keys(storeState).forEach((fnKey) => {
const fn = storeState[fnKey].bind({ $store: store });
resStoreState[fnKey] = computed(fn);
});
return {
uName,
uAge,
uHeight,
...resStoreState,
};
}
封装成hooks如下:
// useState.js
import { computed } from "vue";
import { useStore, mapState } from "vuex";
export default function useState(mapper) {
const store = useStore();
const storeStateFns = mapState(mapper);
const storeState = {};
Object.keys(storeStateFns).forEach((fnKey) => {
const fn = storeStateFns[fnKey].bind({ $store: store });
storeState[fnKey] = computed(fn);
});
return storeState;
}
在组件中使用时
import useState from "@/hooks/useState";
setup() {
// 数组用法
const state = useState(["name", "age", "height"]);
// 对象用法,可使用别名
const stateObj = useState({
uName: (state) => state.name,
uAge: (state) => state.age,
uHeight: (state) => state.height,
});
return {
...state,
...stateObj,
};
}
4.2 mapGetters 辅助函数的封装
其原理与mapState 函数封装类似
// useGetters.js
import { computed } from "vue";
import { mapGetters, useStore } from "vuex";
export default function useGetters(mapper: any) {
const store = useStore();
const storeGettersFns = mapGetters(mapper);
const storeGetters = {};
Object.keys(storeGettersFns).forEach((fnKey) => {
const fn = storeGettersFns[fnKey].bind({ $store: store });
storeGetters[fnKey] = computed(fn);
});
return storeGetters;
}
useState和useGetters两个函数相似度很高,在进一下封装
// useMapper.js
import { computed } from "vue";
import { useStore } from "vuex";
export default function useMapper(mapper, mapFn) {
const store = useStore();
const storeStateFns = mapFn(mapper);
const storeState = {};
Object.keys(storeStateFns).forEach((fnKey) => {
const fn = storeStateFns[fnKey].bind({ $store: store });
storeState[fnKey] = computed(fn);
});
return storeState;
}
// useState.js
import { mapState } from "vuex";
import useMapper from "./useMapper";
export default function useState(mapper) {
return useMapper(mapper, mapState);
}
// useGetters.js
import { mapGetters } from "vuex";
import useMapper from "./useMapper";
export default function useGetters(mapper: any) {
return useMapper(mapper, mapGetters);
}
4.3 对module的支持
useState 和 useGetters 函数暂时还不支持传入命名空间,进一步封装。 useMapper的封装保持不变。
// useState.js
import { createNamespacedHelpers, mapState } from "vuex";
import useMapper from "./useMapper";
export default function useState(mapper, moduleName) {
let mapperFn = mapState;
if (typeof moduleName === "string" && moduleName.length > 0) {
mapperFn = createNamespacedHelpers(moduleName).mapState;
}
return useMapper(mapper, mapperFn);
}
// useGetters.js
import { createNamespacedHelpers, mapGetters } from "vuex";
import useMapper from "./useMapper";
export default function useGetters(mapper, moduleName) {
let mapperFn = mapGetters;
if (typeof moduleName === "string" && moduleName.length > 0) {
mapperFn = createNamespacedHelpers(moduleName).mapGetters;
}
return useMapper(mapper, mapperFn);
}
// 在组件中的使用
// Home.vue
setup() {
const state = useState(["homeCounter"], "home");
const stateGetter = useGetters(["doubleHomeCounter"], "home");
return {
...state,
...stateGetter,
}
}
来源:https://blog.csdn.net/qq_16139383/article/details/119935755


猜你喜欢
- 虽然有些人认为区块链是一个早晚会出现问题的解决方案,但是毫无疑问,这个创新技术是一个计算机技术上的奇迹。那么,究竟什么是区块链呢?区块链以比
- 首先要注意 vue3中 v-model 默认绑定的变量名变了,从原理的 value 改成了 modelValue,如果要改变变量的值,要执行
- 需要在两个文件中实现:首先,在talker.asp(在线名单)中做如下处理:<%p1=trim(application("v
- easy_install 卸载通过easy_install 安装的模块可以直接通过 easy_install -m Packag
- 微信扫码支付分为两种模式,模式一比较复杂,需要公众号配置回调地址。模式二比较简单,只需要在代码中配置回调地址就可以了。我这次使用的是模式二。
- 我的测试环境是2000sever ie6.0+sp4 MYIE1.31 (成功通过测试)关闭窗口的途径常用4种:1.双击左上角图标2.直接双
- 标准库的fnmatch库专门用来进行文件名匹配,支持使用通配符进行字符串匹配。1、fnmatch:判断文件名是否符合特定的模式;2、fnma
- 本文实例讲述了Python线性拟合实现函数与用法。分享给大家供大家参考,具体如下:1. 参考别人写的:#-*- coding:utf-8 -
- 0x01 iframe的跳出框架0x02 iframe样式设置0x03 iframe重置高度1、首先来一个,跳出iframe的好方法,直接可
- 1、使用MySQLdb读取出来的数据是unicode字符串,如果要写入redis的hash中会变成"{u'eth0_out
- 首先介紹一下我們用360搜索派取城市排名前20。我们爬取的网址:https://baike.so.com/doc/24368318-2518
- 最近做百度地图的模拟数据,需要获取某条公交线路沿途站点的坐标信息,貌似百度没有现成的API,因此做了一个模拟页面,工具而已,IE6/7/8不
- 第一:编写限制搜索范围的查询语句。众所周知,在数据库查询的时候返回记录的多少直接关系到查询的效率。所以,在客户端通过一定的条件语句,限制搜索
- 本文实例为大家分享了Vue实现简单跑马灯特效的具体代码,供大家参考,具体内容如下效果:点击按钮让文字动起来,点击停止按钮让文字停止知识点:s
- 1.无效数据的概念无效数据是指不符合数据收集目的或数据收集标准的数据。这些数据可能来自于不准确的测量、缺失值、错误标注、虚假的数据源或其他问
- 现在,我们已经把一个Web App的框架完全搭建好了,从后端的API到前端的MVVM,流程已经跑通了。在继续工作前,注意到每次修改Pytho
- varchar(n)长度为 n 个字节的可变长度且非 Unicode 的字符数据。n 必须是一个介于 1 和 8,000 之间的数值。存储大
- 阅读上一篇:交互设计模式(二)-Pagination(分页,标记页数) Tagging(标签)问题摘要用户往往想通过流行或最详尽的主题来浏览
- 本文实例为大家分享了Linux下MySQL 5.6.27 安装教程,供大家参考,具体内容如下1、下载地址https://cdn.mysql.
- 本文实例讲述了php基于websocket搭建简易聊天室实践。分享给大家供大家参考。具体如下:1、前言公司游戏里面有个简单的聊天室,了解了之