vue3 项目封装vuex的mapxxx, 以及封装请求库
Posted lin_fightin
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了vue3 项目封装vuex的mapxxx, 以及封装请求库相关的知识,希望对你有一定的参考价值。
vuex mapxxx
在vue3的setup中是没有this的,所以我们可以通过vuex提供的useStore来获取store,那辅助函数mapState这些呢?应该其返回的都是函数,且在setup总并没有绑定this,自然也没有store对象,所以我们如果像vue2一样直接使用会报错。
封装 mapActions
我按照vue2的方式使用mapActions,会出现,$store $dispatch不存在的报错,因为setup中没有帮我们绑定this,自然拿不到this. $ store,所以才会报错,解决办法就是手动得其绑定store。
我们可以在中间包一层,获取所有的action然后手动绑上store在返回。使用
其使用稍稍为不同,需要加上模块名。
mutations跟actions是一样的,便不再列出。
封装mapState
因为mapState返回的是一个函数,vue2的话我们是在计算函数中使用它。所以vue3我们要使用计算属性,其返回一个ref的值。
首先根据类型判断是获取哪个模块的辅助函数,接着封装useMapper
使用就是
const { data } = useState(’’, [‘data’])
返回的就是一个对象,其每个属性的值比如data,都是一个ref对象。
封装useAsync请求库
封装一个类似于react的ahooks的useRequest的函数
基本思路是将其发送请求的状态,loading啥的都控制在一起,然后返回给调用的组件使用。
这样在外部就不用定义很多loading,data了。
因为vue3的响应式是reactive,所以要创建一个响应式对象。
比较神奇的是ts,
通过传入的参数request,只要在外部定义该函数的入参是什么类型,如上图的U[],ts就会自动判定,该U是啥类型,所以该函数所有的U就是该类型。不用说在useAsync<x,x>的时候还要给其传入泛型,因为定义的时候已经定义好了,如
ts会自动根据定义的loginApi的入参啊,返回的值类型啊,去定义useAsync中的T,U,而不需要使用useAsync的时候再传一遍。比如useAsync<x,x>这样。
下面是完整代码:
import { reactive, UnwrapRef, toRefs } from "vue";
import { ResProps } from "@/servies/axios";
interface StateProps<T> {
data: T | undefined;
error: Error | null;
loading: boolean;
}
const initState: StateProps<null> = {
data: null,
error: null,
loading: false,
};
const useAsync = <T extends any, U = unknown>(
request: (...args: U[]) => Promise<ResProps<UnwrapRef<T>>>,
options: {
onSuccess?: (data: UnwrapRef<T>) => void;
onError?: (error: Error) => void;
} = {}
) => {
const state = reactive<StateProps<T>>(initState as StateProps<T>);
const { onSuccess, onError } = options;
const setSuccess = (data: UnwrapRef<T>) => {
state.data = data;
state.error = null;
state.loading = false;
};
const setError = (error: UnwrapRef<Error>) => {
state.error = error;
state.loading = false;
};
const run = async (...arg: U[]) => {
if (!state.loading) {
state.loading = true;
}
return await request(...arg)
.then((res) => {
onSuccess && onSuccess(res.data);
setSuccess(res.data);
return Promise.resolve(res.data);
})
.catch((err) => {
setError(err);
onError && onError(err);
return Promise.reject(err);
});
};
return { run, ...toRefs(state) };
};
export { useAsync };
可以尝试下自己封装些东西,对ts的认识以及对封装的概念很有帮助。
vue3的逻辑封装
写vue3d的时候也是体验了一把vue3的逻辑封装,如图
这是一个login组件,其逻辑全被封装到useLogin这个hooks了。
这样就可以每个功能对应一个Hooks,不会像vue2一样所有都要放在一起。有点像react的写法。
改进
在之后的实践中,我发现这种写法
ts检测有问题,比如
返回的对象的属性只要是字符串类型都行,什么意思呢?如
使用的时候,明明之传入三个,但却可以输入解构a,b却不报错,通过了ts的检测,证明我们的写法有问题,
不能只简简单单这样定义返回的对象,因为args为string[],自然
该对象的ts定义就类似于Record<string, ActionMethod>这样。不行的,我们必须根据传入的具体值来确定返回的类型,稍作改进之后
现在我们可以接受一个泛型入参T,它必须是string类型的,但是这个T的具体实现可以通过传入的数组的值来推导而出。
现在看效果
必须是你传入什么就是什么
返回的对象的定义也是根据T来的了,所以现在你传入什么值就会对应输出什么值。
useMapper的封装也要改。
以上是关于vue3 项目封装vuex的mapxxx, 以及封装请求库的主要内容,如果未能解决你的问题,请参考以下文章
vue3 封装使用 pinia (可直接使用,包含数据持久化)
vue-cli4 项目框架的搭建 以及 路由的封装axios的封装公共函数js文件的封装引用vuex的基本用法minins混入css以及字体图标和图片的引入等