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)
ultrinfaern
26.04.2024 10:37Как я понимаю, смысл инжекта, чтобы его потом можно было использовать в темплейте. Если в темплейте оно не нужно, то можно просто импорировать как модуль в скрипте.
Во вторых, при инжекте есть значение по умолчанию, и взможен такой вариант: в скрипте импортируем модуль, и инжектим его под любым именем, указывая значение по умолчанию.
Все это не касается, когдава нужно что-то передать от одного компонета к другому прыгая далеко по их иерархии - там только классическое provide/inject
ThePussyMaster Автор
26.04.2024 10:37Все верно, типизированный запрос в темплейте, либо обычный импорт в модуле
Djaler
26.04.2024 10:37+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>
gmtd
26.04.2024 10:37off-top
Что хочет сказать и ожидает получить человек, на техническом сайте регистрирующийся с ником ThePussyMaster?
Zer0S2m
Добрый день!
А в чем этот метод реализации лучше, чем простое импортирование из файла
index.ts
и описание запросов в нем?gmtd
Самобытный, уникальный, нигде ни у кого больше такого нет.
ThePussyMaster Автор
Этот метод позволяет типизировать запросы в темплейте. В модуль импортируется и используется как обычно. Описание запросов в любом случае лучше выносить в отдельный файл.