You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vue3单例Axios实例在事件处理器中调用时inject报错求助

问题描述

我编写了一个用于创建Axios实例的Vue插件,全局注册后,在组件setup阶段调用封装的API方法可正常使用该实例,但在按钮点击这类事件处理器中调用时,会报错:inject() can only be used inside setup() or functional components.。相关代码如下:

plugins/axios.ts

import axios from 'axios'
import type { App } from 'vue'

interface AxiosOptions {
    baseUrl: string
}

function isIsoDateString(value: any): boolean {
    ...
}

function handleDates(body: any) {
   ...
}

export default {
    install: (app: App, options: AxiosOptions) => {

        const axiosInstance = axios.create({
            baseURL: options.baseUrl,
            headers: {
                "Accept": "application/json",
                "Content-type": "application/json"
            }
        });
        
        axiosInstance.interceptors.response.use(originalResponse => {
            handleDates(originalResponse.data);
            return originalResponse;
        });

        app.provide("axios", axiosInstance);
    }
}

main.ts

import { createApp } from "vue";
import { createPinia } from "pinia";
import mitt from "mitt";

import axios from "@/plugins/axios";
import App from "./App.vue"
import router from "./router";

const emitter = mitt();

const app = createApp(App)
    .use(router)
    .use(createPinia())
    .use(axios, {baseUrl: "http://localhost:15454/"});

app.provide("emitter", emitter);
app.mount("#app");

actions/providers.ts

import { inject } from 'vue'
import type { AxiosInstance } from 'axios';
import { type Provider } from "../types/Provider";


export const getProviders = async (activeOnly: boolean): Promise<Provider[]> => {

    const ax = inject('axios') as AxiosInstance;

    try {

        const response = await ax.get(`/Provider/${activeOnly}`);
        return response.data;

    } catch (error) {
        ...
        return [];
    }
};

报错场景代码

<script setup lang="ts">
    const handleClick = async () => {
        const value = await getProviders(true);
    }
</script>
<template>
    <button @click="handleClick">Submit</button>
</template>
报错原因

inject() 是Vue Composition API的方法,必须在组件的setup上下文执行期间调用。你的getProviders函数里直接调用了inject('axios'):

  • 当在组件setup阶段调用getProviders时,setup上下文还存在,inject能正常获取到提供的Axios实例;
  • 当在事件处理器(比如按钮点击)中调用时,setup已经执行完毕,此时调用getProviders,inject找不到当前组件的上下文,就会抛出错误。
解决方案

下面提供三种可行的解决方法,按需选择:

方法一:在组件中注入实例后传给API函数

修改API函数,让它接收Axios实例作为参数,不再内部调用inject:

修改actions/providers.ts

import type { AxiosInstance } from 'axios';
import { type Provider } from "../types/Provider";

export const getProviders = async (axiosInstance: AxiosInstance, activeOnly: boolean): Promise<Provider[]> => {
    try {
        const response = await axiosInstance.get(`/Provider/${activeOnly}`);
        return response.data;
    } catch (error) {
        // 错误处理逻辑
        return [];
    }
};

修改组件代码

<script setup lang="ts">
import { inject } from 'vue'
import type { AxiosInstance } from 'axios';
import { getProviders } from '@/actions/providers';

// 在setup阶段注入Axios实例
const axiosInstance = inject('axios') as AxiosInstance;

const handleClick = async () => {
    // 调用时传入实例
    const value = await getProviders(axiosInstance, true);
}
</script>
<template>
    <button @click="handleClick">Submit</button>
</template>

方法二:将Axios实例挂载到全局属性

修改插件,把Axios实例同时挂载到Vue应用的全局属性上,这样可以在组件中直接获取:

修改plugins/axios.ts的install方法

export default {
    install: (app: App, options: AxiosOptions) => {
        const axiosInstance = axios.create({
            baseURL: options.baseUrl,
            headers: {
                "Accept": "application/json",
                "Content-type": "application/json"
            }
        });
        
        axiosInstance.interceptors.response.use(originalResponse => {
            handleDates(originalResponse.data);
            return originalResponse;
        });

        app.provide("axios", axiosInstance);
        // 添加这行,挂载到全局属性
        app.config.globalProperties.$axios = axiosInstance;
    }
}

修改组件代码

<script setup lang="ts">
import { getCurrentInstance } from 'vue'
import { getProviders } from '@/actions/providers';

// 获取当前组件实例的代理
const { proxy } = getCurrentInstance()!;

const handleClick = async () => {
    // 从全局属性获取实例并传入API函数
    const value = await getProviders(proxy!.$axios, true);
}
</script>

方法三:直接导出Axios实例(推荐)

放弃provide/inject的方式,直接在模块中创建并导出Axios实例,这样API函数可以直接导入使用,不依赖组件上下文:

修改plugins/axios.ts

import axios from 'axios';
import type { AxiosInstance } from 'axios';

interface AxiosOptions {
    baseUrl: string
}

function isIsoDateString(value: any): boolean {
    ...
}

function handleDates(body: any) {
   ...
}

// 声明实例变量
export let axiosInstance: AxiosInstance;

// 初始化方法
export const initAxios = (options: AxiosOptions) => {
    axiosInstance = axios.create({
        baseURL: options.baseUrl,
        headers: {
            "Accept": "application/json",
            "Content-type": "application/json"
        }
    });
    
    axiosInstance.interceptors.response.use(originalResponse => {
        handleDates(originalResponse.data);
        return originalResponse;
    });
}

修改main.ts

import { createApp } from "vue";
import { createPinia } from "pinia";
import mitt from "mitt";

import { initAxios } from "@/plugins/axios";
import App from "./App.vue"
import router from "./router";

const emitter = mitt();

// 先初始化Axios实例
initAxios({baseUrl: "http://localhost:15454/"});

const app = createApp(App)
    .use(router)
    .use(createPinia());

app.provide("emitter", emitter);
app.mount("#app");

修改actions/providers.ts

import { axiosInstance } from '@/plugins/axios';
import { type Provider } from "../types/Provider";

export const getProviders = async (activeOnly: boolean): Promise<Provider[]> => {
    try {
        const response = await axiosInstance.get(`/Provider/${activeOnly}`);
        return response.data;
    } catch (error) {
        // 错误处理逻辑
        return [];
    }
};

组件代码无需修改

此时不管在setup还是事件处理器中调用getProviders,都能正常使用Axios实例,无需额外处理。


内容的提问来源于stack exchange,提问作者Leigh.D

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 09:33:20