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 && (
+
+ )}
+
+
+ );
+}
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 && (
-
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"
/>