126 lines
6.0 KiB
Markdown
126 lines
6.0 KiB
Markdown
### Пару важливих речей:
|
||
- Метод = функція
|
||
- Класс != тип - в TS є такі штуки як `AxiosResponse<IResponse<T>, any>` і потрібно розуміти що ці штуки працюють зовсім по другому. Навіть якщо я десь забув поправити - це важливо памʼятати
|
||
- any = unknown - формально мені б любий Senior Typescript девелопер язика за таке відірвав, але в цілому тут воно має різницю тільки в тому що при використанні того чи іншого ESlint видає різні помилки які треба виправляти. Це typescript, розслабся і получай задоволення
|
||
|
||
загальний перелік інструментів та ліб:
|
||
|
||
- tanstack query
|
||
- axios
|
||
|
||
піду з кінця:
|
||
|
||
коли ти хочеш відправити реквест на сервак, чи то Get чи то Post, звичайно це робиться через створений hook:
|
||
|
||
```ts
|
||
import { useQuery } from "@tanstack/react-query";
|
||
import { gameService } from "@/shared/services/game.service";
|
||
import { transformApiDataToGames } from "../components/gamesSlider/gamesSlider.utils";
|
||
|
||
export const useGetGames = () => {
|
||
const query = useQuery({
|
||
queryKey: ["games"],
|
||
queryFn: gameService.getGames,
|
||
});
|
||
|
||
const games =
|
||
query.data && query.data.length > 0
|
||
? transformApiDataToGames(query.data)
|
||
: [];
|
||
|
||
return { games, ...query };
|
||
};
|
||
|
||
```
|
||
|
||
тут можна побачити декілька речей:
|
||
|
||
- хук використовує tanstack query для реквесту
|
||
- танстак використовує допоміжну функцію класу GameService визначену в папці shared/services/
|
||
- Після отримання даних, воно перетворюється на локальний класс Game, достатньо незручний спосіб, краще його не використовувати, але в цьому випадку було необхідно
|
||
|
||
тепер як видно по цим речам, нам треба допоможна сервісна функція, яка використовує не просто fetch(), а повноцінний написаний Діаною http service:
|
||
```ts
|
||
import { HttpService } from "./http.service";
|
||
import { axiosClient } from "./axios-client";
|
||
import { IGameApiResponse } from "../types/game.types";
|
||
|
||
export class GameService extends HttpService {
|
||
getGames = async () => {
|
||
const response = await this.get<IGameApiResponse[]>(`rpg-events`);
|
||
return response;
|
||
};
|
||
}
|
||
|
||
export const gameService = new GameService(axiosClient);
|
||
|
||
```
|
||
|
||
тут можна побачити що достає з сервака цей реквест, і що воно привʼязана до клієнта аксіоса, який і дозволяє використовувати http протокол.
|
||
|
||
подивившись ближче, можна побачити що в файлі https.service.ts є імплементація axiosClient - НЕ ДИВИСЬ НА НЕЇ - це дефолт, і він в нашому випадку на самий крайній випадок, справжня імплементація axiosClient яка використовується ось тут:
|
||
```ts
|
||
export const gameService = new GameService(axiosClient);
|
||
```
|
||
виходить з файлу axios-client.ts (я потратив не одну годину шукаючи і розбираючись що і де)
|
||
|
||
|
||
Отже, axiosClient є імплементацією яка повністю повинна замінити fetch(), та з досвіду - працює набагато краще
|
||
|
||
Те що найголовніше для фетчингу ігор є в цій функції get:
|
||
|
||
```ts
|
||
public async get<T>(
|
||
url: string,
|
||
config?: IHttpConfig,
|
||
): Promise<AxiosResponse<IResponse<T>, any>> {
|
||
const response = await this.axiosInstance.get<IResponse<T>>(
|
||
url,
|
||
config as AxiosRequestConfig,
|
||
);
|
||
|
||
return response;
|
||
}
|
||
```
|
||
звідси треба розуміти тільки те що `Promise<AxiosResponse<IResponse<T>, any>>` це тип, який проходить через ще один шар, що є в класі HttpService.
|
||
```ts
|
||
public async get<T>(url: string, config?: IHttpConfig): Promise<T> {
|
||
return this.fetchingService
|
||
.get<AxiosResponse<IResponse<T>, unknown>>(this.getFullApiUrl(url), {
|
||
...config,
|
||
headers: {
|
||
...config?.headers,
|
||
...this.populateContentTypeHeaderConfig(),
|
||
},
|
||
})
|
||
.then((result) => {
|
||
this.checkResponseStatus(result);
|
||
return result.data as T;
|
||
});
|
||
}
|
||
|
||
// допоміжна функція для знаходження повного url
|
||
// працює дивно коли в url є localhost, але якщо вписати в NEXT_PUBLIC_BACKEND_URL=https://inrium.org.ua/api то буде працювати бездоганно
|
||
private getFullApiUrl(url: string): string {
|
||
return `${this.baseUrl}/${url}`;
|
||
}
|
||
```
|
||
|
||
ось це і є та самий метод який є тут, та який тобі і вертає T напряму звідси:
|
||
```ts
|
||
// rpg-events - частина повної url: http[s]://[NEXT_PUBLIC_BACKEND_URL | BASE_URL]/api/rpg-events.
|
||
const response = await this.get<IGameApiResponse[]>(`rpg-events`);
|
||
return response
|
||
```
|
||
|
||
тому response в цьому випадку має тип `IGameApiResponse[]`.
|
||
|
||
В загальному це виглядає так:
|
||
|
||
`request by hook -> http.service -> axios-client`
|
||
axios-client фетчить потрібні дані з сервака, і якщо помилок немає то передає на `const response`
|
||
|
||
# Не бійся задавати найпростіші та найтупіші питання, відповім на все
|
||
|
||
|