import { selectDurationItems, sortItemsDefault, selectAddedItems } from '../../lib'; import type { Language } from '../../runtime'; import { AsyncData, getSelectedQuery } from '../../runtime'; import type { INavLinkItem, IVideoCard, PaginatedResponse } from '../../types'; import { useRoute } from 'vue-router'; export const useFetchVideos = async ( apiMethod: (...args: any[]) => Promise>, // defaultOrder всегда непустой: в запрос уходит либо выбранная сортировка, либо дефолтная { sortItems = sortItemsDefault, defaultOrder = '-country_order' }: { sortItems?: INavLinkItem[], defaultOrder?: string } = {} ) => { const route = useRoute(); const mobile = !!useState('isMobile').value; const perPage = mobile ? 12 : 48; const lang = useLang() as Language; const filters = computed(() => useGetVideosFilterRequest(route, selectDurationItems, selectAddedItems)); const key = AsyncData.Videos; const stateKey = computed(() => `data-${key}-${route.path}-${JSON.stringify(route.query)}-${lang}`); // Ключ уникален на path+query+lang (не константа AsyncData.Videos): иначе, во-первых, главная // делит один кэш-слот между разными query (page/sort/фильтры) и при возврате на неё отдаётся // кэш от другого состояния вместо свежего фетча (мигает «нет данных»/пустой грид); во-вторых, // главная и /search/{slug}/videos (обе на useFetchVideos, но с разными apiMethod) сходятся в // один ключ — Nuxt оставляет обработчик, зарегистрированный первым, и на главную приходит // выдача video-search-by-niche. const { data, status, error } = await useAsyncData>( stateKey.value, () => useApiFetcher>( stateKey.value, apiMethod, lang, { page: Number(route.query['page']) || 1, ['per-page']: perPage, }, filters.value, getSelectedQuery(route, sortItems) || defaultOrder )(), { watch: [ () => { if (route.query) { const currentQuery = route.query; return JSON.stringify(currentQuery); } }, ], } ); return { data, status, error }; };