Vue 2

В Vue 2 нам бы пришлось использовать Vue.prototype, чтобы добавить глобальные свойства к экземпляру Vue. Но в Vue 3 мы получили "Composition API"

Итак, рекомендуемый способ добавления глобальных свойств с помощью composition api это использовать provide/inject. Поскольку config.globalProperties рассматривается как аварийный выход.

config.globalProperties

Свойства config.globalPropertiesпредназначены для репликации поведения Vue.prototype. В функции setupпросто импортируйте то, что вам нужно, или явно используйте provide/inject, чтобы предоставить свойства приложению.

Создаем файл /api/index.ts

import axios, { AxiosInstance } from 'axios';

const apiClient: AxiosInstance = axios.create({
    baseURL: import.meta.env.VITE_BASE_URL,
    headers: {
        'Content-type': 'application/json'
    }
});

export default apiClient;

Это наш глобальный экземпляр Axios с опциями

Создаем файл /api/symbols.ts

import { InjectionKey } from 'vue';
import { AxiosInstance } from 'axios';

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

Это необходимо для возможности типизации Provide/inject

В файле main.ts

import http from '@/api/index';
import { AxiosKey } from '@/api/symbols';

createApp(App).provide(AxiosKey, http)

Мы предоставляем наш экземпляр Axios глобально, используя Injection Key - AxiosKey, поэтому теперь он типизируется. В противном случае вам пришлось бы вводить типы каждый раз, при использовании inject()

Создаем файл /api/injectTyped.ts

import { inject, InjectionKey } from 'vue';

/* Функция для работы с неопределенными значениями в inject() */
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;
}
итоговая структура файлов
итоговая структура файлов

Создаем функцию composable в /composables/Api.ts

import { injectStrict } from '@/api/injectTyped';
import { AxiosKey } from '@/api/symbols';

/* Для глобального доступа и типизации запросов */
export const useApi = () => injectStrict(AxiosKey);

Использование

<script setup lang="ts">
import { useApi } from '@/composables/Api';
const http = useApi();

interface HabrPosts {
    id: string;
    label: string;
}

onMounted(async () => {
    await http.get<HabrPosts[]>('/articles');
});
</script>

Теперь у нас есть удобная глобальная и типизируемая прослойка по работе с API

Комментарии (8)


  1. Zer0S2m
    26.04.2024 10:37
    +2

    Добрый день!

    А в чем этот метод реализации лучше, чем простое импортирование из файла index.ts и описание запросов в нем?

    Пример
    Пример


    1. gmtd
      26.04.2024 10:37

      Самобытный, уникальный, нигде ни у кого больше такого нет.


    1. ThePussyMaster Автор
      26.04.2024 10:37

      Этот метод позволяет типизировать запросы в темплейте. В модуль импортируется и используется как обычно. Описание запросов в любом случае лучше выносить в отдельный файл.


  1. ultrinfaern
    26.04.2024 10:37

    Как я понимаю, смысл инжекта, чтобы его потом можно было использовать в темплейте. Если в темплейте оно не нужно, то можно просто импорировать как модуль в скрипте.

    Во вторых, при инжекте есть значение по умолчанию, и взможен такой вариант: в скрипте импортируем модуль, и инжектим его под любым именем, указывая значение по умолчанию.

    Все это не касается, когдава нужно что-то передать от одного компонета к другому прыгая далеко по их иерархии - там только классическое provide/inject


    1. ThePussyMaster Автор
      26.04.2024 10:37

      Все верно, типизированный запрос в темплейте, либо обычный импорт в модуле


      1. Djaler
        26.04.2024 10:37
        +1

        В темплейте или компоненте? В темплейте запросы делать уж точно не стоит)
        А код компонента - такой же модуль, как и остальные.


  1. Djaler
    26.04.2024 10:37
    +1

    рекомендуемый способ добавления глобальных свойств

    это не добавлять глобальные свойства. А в примере вообще не видно смысла в этом. Просто импортируем нужный объект и все, к чему тут provide-inject?

    <script setup lang="ts">
    import http from '@/api/index';
    
    interface HabrPosts {
        id: string;
        label: string;
    }
    
    onMounted(async () => {
        await http.get<HabrPosts[]>('/articles');
    });
    </script>


  1. gmtd
    26.04.2024 10:37

    off-top

    Что хочет сказать и ожидает получить человек, на техническом сайте регистрирующийся с ником ThePussyMaster?