Commit c389dc76 authored by tom goriunov's avatar tom goriunov Committed by GitHub

reduce /node-api/media-type calls, when some nft media have the same urls (#1191)

Fixes #1180
parent c18c5c91
...@@ -2,17 +2,11 @@ import { AspectRatio, chakra, Skeleton, useColorModeValue } from '@chakra-ui/rea ...@@ -2,17 +2,11 @@ import { AspectRatio, chakra, Skeleton, useColorModeValue } from '@chakra-ui/rea
import React from 'react'; import React from 'react';
import { useInView } from 'react-intersection-observer'; import { useInView } from 'react-intersection-observer';
import type { StaticRoute } from 'nextjs-routes';
import { route } from 'nextjs-routes';
import useFetch from 'lib/hooks/useFetch';
import NftFallback from './NftFallback'; import NftFallback from './NftFallback';
import NftHtml from './NftHtml'; import NftHtml from './NftHtml';
import NftImage from './NftImage'; import NftImage from './NftImage';
import NftVideo from './NftVideo'; import NftVideo from './NftVideo';
import type { MediaType } from './utils'; import useNftMediaType from './useNftMediaType';
import { getPreliminaryMediaType } from './utils';
interface Props { interface Props {
url: string | null; url: string | null;
...@@ -21,44 +15,13 @@ interface Props { ...@@ -21,44 +15,13 @@ interface Props {
} }
const NftMedia = ({ url, className, isLoading }: Props) => { const NftMedia = ({ url, className, isLoading }: Props) => {
const [ type, setType ] = React.useState<MediaType | undefined>();
const [ isMediaLoading, setIsMediaLoading ] = React.useState(Boolean(url)); const [ isMediaLoading, setIsMediaLoading ] = React.useState(Boolean(url));
const [ isLoadingError, setIsLoadingError ] = React.useState(false); const [ isLoadingError, setIsLoadingError ] = React.useState(false);
const bgColor = useColorModeValue('blackAlpha.50', 'whiteAlpha.50'); const bgColor = useColorModeValue('blackAlpha.50', 'whiteAlpha.50');
const fetch = useFetch();
const { ref, inView } = useInView({ triggerOnce: true }); const { ref, inView } = useInView({ triggerOnce: true });
const type = useNftMediaType(url, !isLoading && inView);
React.useEffect(() => {
if (!url || isLoading || !inView) {
return;
}
// media could be either image, gif or video
// so we pre-fetch the resources in order to get its content type
// have to do it via Node.js due to strict CSP for connect-src
// but in order not to abuse our server firstly we check file url extension
// and if it is valid we will trust it and display corresponding media component
const preliminaryType = getPreliminaryMediaType(url);
if (preliminaryType) {
setType(preliminaryType);
return;
}
const mediaTypeResourceUrl = route({ pathname: '/node-api/media-type' as StaticRoute<'/api/media-type'>['pathname'], query: { url } });
fetch(mediaTypeResourceUrl)
.then((_data) => {
const data = _data as { type: MediaType | undefined };
setType(data.type || 'image');
})
.catch(() => {
setType('image');
});
}, [ url, isLoading, fetch, inView ]);
const handleMediaLoaded = React.useCallback(() => { const handleMediaLoaded = React.useCallback(() => {
setIsMediaLoading(false); setIsMediaLoading(false);
......
import { useQuery } from '@tanstack/react-query';
import type { StaticRoute } from 'nextjs-routes';
import { route } from 'nextjs-routes';
import type { ResourceError } from 'lib/api/resources';
import useFetch from 'lib/hooks/useFetch';
import type { MediaType } from './utils';
import { getPreliminaryMediaType } from './utils';
export default function useNftMediaType(url: string | null, isEnabled: boolean) {
const fetch = useFetch();
const { data } = useQuery<unknown, ResourceError<unknown>, MediaType>(
[ 'nft-media-type', url ],
async() => {
if (!url) {
return 'image';
}
// media could be either image, gif, video or html-page
// so we pre-fetch the resources in order to get its content type
// have to do it via Node.js due to strict CSP for connect-src
// but in order not to abuse our server firstly we check file url extension
// and if it is valid we will trust it and display corresponding media component
const preliminaryType = getPreliminaryMediaType(url);
if (preliminaryType) {
return preliminaryType;
}
try {
const mediaTypeResourceUrl = route({ pathname: '/node-api/media-type' as StaticRoute<'/api/media-type'>['pathname'], query: { url } });
const response = await fetch<{ type: MediaType | undefined }, ResourceError>(mediaTypeResourceUrl);
return 'type' in response ? response.type ?? 'image' : 'image';
} catch (error) {
return 'image';
}
},
{
enabled: isEnabled && Boolean(url),
staleTime: Infinity,
});
return data;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment