在vue3的hook中结合TypeScript使用vue-axios

1,128 阅读2分钟

背景

vue-axios官方文档提供的说明方法中使用了any类型,导致我们使用的时候无法推断类型,官方例子如下:

// main.ts
import { createApp } from 'vue'
import App from './App.vue'
import store from './store'
import axios from 'axios'
import VueAxios from 'vue-axios'

const app = createApp(App).use(store)
app.use(VueAxios, axios)
app.provide('axios', app.config.globalProperties.axios)  // provide 'axios'
app.mount('#app')

// App.vue
import { inject } from 'vue'

export default {
  name: 'Comp',
  setup() {
    const axios: any = inject('axios')  // inject axios

    const getList = (): void => {
      axios
        .get(api)
        .then((response: { data: any }) => {
          console.log(response.data)
        });
    };

    return { getList }
  }
}

在项目中的使用方式

改造以下官方例子,使之符合我们的项目规范。

首先,创建以下几个文件:

创建一个symbols.ts文件存放我们的inject类型的key

创建一个useAxios.ts文件,作为hook使用axios

其次,在main.ts引入useAxios.ts

// symbols.ts
export const AxiosKey = Symbol('axios');


// useAxios.ts
import axios from 'axios';
import VueAxios from 'vue-axios';
import { App } from 'vue';
import { AxiosKey } from './symbols';

export function useAxios(app: App) {
  axios.interceptors.response.use( // 添加响应拦截器
    function (response) { 
      return response.data;  // 只返回响应的数据,不返回其他配置信息
    },
    function (error) {
      return Promise.reject(error);  // 对响应错误做点什么
    }
  );
  // 更多操作...

  app.use(VueAxios, axios);
  app.provide(AxiosKey, app.config.globalProperties.axios);
}


// main.ts
import { useAxios } from './useAxios';

const app = createApp(App);
useAxios(app); // 使用vue-axios

其次,通过以上步骤,接下来我们就可以在hook中使用axios

// useTable.ts
import { inject, ref } from 'vue';
import { AxiosKey } from './symbols';

export default function useTable() {
     const axios: any = inject(AxiosKey);
     
     const fetchList = () => {
         axios.get('urlxx', {
             params: {
                 id: '123'
             }
         }).then((res) => {
             console.log(res.data);
         })
     }
}

解决any问题

上面的hookaxios还是any类型的,接下来我们改造一下,解决any问。借助InjectionKey方法把类型注入。

改造symbols.ts为如下:

// symbols.ts
import { InjectionKey } from 'vue';
import { AxiosInstance } from 'axios';

export const AxiosKey: InjectionKey<AxiosInstance> = Symbol('axios');

修改hook,去掉any

// useTable.ts
import { inject, ref } from 'vue';
import { AxiosKey } from './symbols';

export default function useTable() {
     const axios = inject(AxiosKey);
     
     const fetchList = () => {
         axios.get('urlxx', {
             params: {
                 id: '123'
             }
         }).then((res) => {
             console.log(res.data);
         })
     }
}

但是还有问题,inject的时候会出现undefined提示,这时候需要对inject方法进行封装一下,放在utils.ts文件中

// util.ts
import { inject, InjectionKey } from 'vue';

/**
 * 解决使用inject的时候undefined问题
 * @param key
 * @param fallback
 * @returns
 */
export function injectStrict<T>(key: InjectionKey<T>, fallback?: T) {
  const resolved = inject(key, fallback);

  if (!resolved) {
    throw new Error(`Could not resolve ${key.description}`);
  }

  return resolved;
}

此时,在hook中使用injectStrict替换inject

// useTable.ts
import { inject, ref } from 'vue';
import { AxiosKey } from './symbols';
import { injectStrict } from './utils';

export default function useTable() {
     const axios = injectStrict(AxiosKey);
     
     const fetchList = () => {
         axios.get('urlxx', {
             params: {
                 id: '123'
             }
         }).then((res) => {
             console.log(res.data);
         })
     }
}

通过以上操作,any问题彻底解决。

最终代码

// symbols.ts
import { InjectionKey } from 'vue';
import { AxiosInstance } from 'axios';

export const AxiosKey: InjectionKey<AxiosInstance> = Symbol('axios');


// util.ts
import { inject, InjectionKey } from 'vue';

/**
 * 解决使用inject的时候undefined问题
 * @param key
 * @param fallback
 * @returns
 */
export function injectStrict<T>(key: InjectionKey<T>, fallback?: T) {
  const resolved = inject(key, fallback);

  if (!resolved) {
    throw new Error(`Could not resolve ${key.description}`);
  }

  return resolved;
}


// useAxios.ts
import axios from 'axios';
import VueAxios from 'vue-axios';
import { App } from 'vue';
import { AxiosKey } from './symbols';

export function useAxios(app: App) {
  axios.interceptors.response.use( // 添加响应拦截器
    function (response) { 
      return response.data;  // 只返回响应的数据,不返回其他配置信息
    },
    function (error) {
      return Promise.reject(error);  // 对响应错误做点什么
    }
  );
  // 更多操作...

  app.use(VueAxios, axios);
  app.provide(AxiosKey, app.config.globalProperties.axios);
}


// main.ts
import { useAxios } from './useAxios';

const app = createApp(App);
useAxios(app); // 使用vue-axios


// useTable.ts
import { inject, ref } from 'vue';
import { AxiosKey } from './symbols';
import { injectStrict } from './utils';

export default function useTable() {
     const axios = injectStrict(AxiosKey);
     
     const fetchList = () => {
         axios.get('urlxx', {
             params: {
                 id: '123'
             }
         }).then((res) => {
             console.log(res.data);
         })
     }
}

相关文章

# Using axios globally in a Vue 3 with provide/inject (composition API)