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 (可直接使用,包含数据持久化)

vue3+uniapp封装请求总是出错

vue-cli4 项目框架的搭建 以及 路由的封装axios的封装公共函数js文件的封装引用vuex的基本用法minins混入css以及字体图标和图片的引入等

我把 Vue3 项目中的 Vuex 去除了,改用 Pinia

vue3 项目添加vuex 进行组件中传递数据

VUE3项目实现动态路由demo