Ben Carey
Ben Carey

Reputation: 16968

Access instance/service from Vuex that was provided to Vue (Vue.js 3)

Background

Consider the following:

// app.js
import API from 'utils/API';

const api = new API(config.app.urls.api, endpoints, token);

app.provide('$api', api);

Based on everything I have read in the past 24 hours, the above is the advised method of providing a 'service' to Vue.js 3.

However, the issue with the above is that I now cannot access the API instance as the inject method cannot be used outside of a Vue component.

As such, when I want to import the API instance into my Vuex modules, I can't...

Question

Is there an 'advised' way of accessing a provided service outside of a Vue component? Or is one of my proposed solutions below how it should be done?

Possible Solutions

Proposed Solution 1

Instead of providing the service to Vue, we can just add it to the global properties like so:

// app.js
app.config.globalProperties.$api = api;

and then we can access it like so in the store:

// some-vuex-module.js
import { getCurrentInstance } from 'vue';

const api = getCurrentInstance().appContext.config.globalProperties.$api;

I am using the above for certain things in my app but for the API service it just seems wrong to do it this way.

Proposed Solution 2

Another solution I thought of was to just make the API instance available to the window like so:

// app.js
import API from 'utils/API';

const api = window.api = new API(config.app.urls.api, endpoints, token);

app.provide('$api', api);

The above seems like an anti-pattern though...

Upvotes: 3

Views: 1367

Answers (1)

Estus Flask
Estus Flask

Reputation: 223074

The preferable method in modular environment (which Vue 3 setup is commonly is) is to just import api in places where it's used, regardless of whether it's used inside or outside the component.

The solution with Vue global property originated at the time when Vue applications weren't necessarily modular so they relied on Vue instance as global application scope. Currently it's suitable only for properties that are primarily used in a template and require boilerplate code to import and expose them. The example is $t in vue-i18n.

The solution with provide/inject is usable for cases that need dependency injection. A common case is a library that require dependencies to be loosely coupled. Another one is that a dependency depends on component hierarchy and may vary between components.

The solution with window should be avoided, unless application is divided into separate scripts that cannot interact through common JS modules. Even then the problem is that a script that defines global variable should be loaded before those that use it.

Upvotes: 3

Related Questions