diff --git a/src/components/LazyImage.tsx b/src/components/LazyImage.tsx new file mode 100644 index 0000000..df3ea29 --- /dev/null +++ b/src/components/LazyImage.tsx @@ -0,0 +1,43 @@ +import { useInView } from "react-intersection-observer"; + +type LazyImageProps = { + src: string; + alt: string; + onLoad?: () => void; + onChange?: (inView: boolean) => void; + className?: string; + offset?: string; +}; + +export default function LazyImage({ + src, + alt, + onLoad, + onChange, + className, + offset = "0px", +}: LazyImageProps) { + const { ref, inView } = useInView({ onChange }); + + return ( +
+ {inView && ( + {alt} + )} +
+
+ ); +} diff --git a/src/pages/Browse/ExtensionBrowse.tsx b/src/pages/Browse/ExtensionBrowse.tsx index b8caa64..c4745ac 100644 --- a/src/pages/Browse/ExtensionBrowse.tsx +++ b/src/pages/Browse/ExtensionBrowse.tsx @@ -1,6 +1,5 @@ import { forwardRef, useEffect, useState } from "react"; import { Link, useParams } from "react-router-dom"; -import { useInView } from "react-intersection-observer"; import { Extension } from "../../types/extension.ts"; import { Manga } from "../../types/manga.ts"; @@ -8,6 +7,7 @@ import { getMangaList } from "../../services/extensions.service.ts"; import { useStore } from "../../services/store.service.ts"; import { downloadImage } from "../../services/tauri.service.ts"; import useInfiniteScroll from "../../utils/infinite-scroll-hook.ts"; +import LazyImage from "../../components/LazyImage.tsx"; export default function ExtensionBrowse() { const { extensionId } = useParams(); @@ -115,13 +115,6 @@ const MangaItem = ( ) => { const [src, setSrc] = useState(null); const [loading, setLoading] = useState(true); - const offset = "200vh"; - - const { ref, inView } = useInView({ - onChange: (inView) => { - if (inView) setLoading(true); - }, - }); useEffect(() => { downloadImage(manga.coverUrl, 300, 450).then((bytes) => { @@ -137,25 +130,18 @@ const MangaItem = ( to={{ pathname: `/browse/${extensionId}/${manga.id}` }} state={manga} > -
- {inView && ( - {manga.title} setLoading(false)} - className={`w-full h-full object-cover rounded-md transition-opacity duration-300 ${ - loading ? "opacity-0" : "opacity-1" - }`} - /> - )} -
+ setLoading(false)} + onChange={(inView) => { + if (inView) setLoading(true); }} + className={`w-full h-full object-cover rounded-md transition-opacity duration-300 ${ + loading ? "opacity-0" : "opacity-1" + }`} + offset="200vh" />