feat: thumbnail and observer to load only viewed

This commit is contained in:
Julien Froidefond
2025-02-19 20:58:45 +01:00
parent e7742f8638
commit a91d9dfd54

View File

@@ -6,14 +6,24 @@ import { forwardRef, useEffect, useState, useCallback, useRef } from "react";
export const Thumbnail = forwardRef<HTMLButtonElement, ThumbnailProps>( export const Thumbnail = forwardRef<HTMLButtonElement, ThumbnailProps>(
( (
{ pageNumber, currentPage, onPageChange, getThumbnailUrl, loadedThumbnails, onThumbnailLoad }, {
pageNumber,
currentPage,
onPageChange,
getThumbnailUrl,
loadedThumbnails,
onThumbnailLoad,
isVisible,
},
ref ref
) => { ) => {
const [imageUrl, setImageUrl] = useState<string | null>(null); const [imageUrl, setImageUrl] = useState<string | null>(null);
const [isLoading, setIsLoading] = useState(true); const [isLoading, setIsLoading] = useState(true);
const [hasError, setHasError] = useState(false); const [hasError, setHasError] = useState(false);
const [isInViewport, setIsInViewport] = useState(false);
const loadAttempts = useRef(0); const loadAttempts = useRef(0);
const maxAttempts = 3; const maxAttempts = 3;
const thumbnailRef = useRef<HTMLButtonElement>(null);
const resetLoadingState = useCallback(() => { const resetLoadingState = useCallback(() => {
setIsLoading(true); setIsLoading(true);
@@ -21,7 +31,37 @@ export const Thumbnail = forwardRef<HTMLButtonElement, ThumbnailProps>(
loadAttempts.current = 0; loadAttempts.current = 0;
}, []); }, []);
// Observer pour détecter quand la thumbnail est dans le viewport
useEffect(() => { useEffect(() => {
//if (!isVisible) return; // Ne pas observer si la barre est cachée
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
setIsInViewport(entry.isIntersecting);
});
},
{
rootMargin: "50px",
}
);
const element = thumbnailRef.current;
if (element) {
observer.observe(element);
}
return () => {
if (element) {
observer.unobserve(element);
}
};
}, [isVisible]);
// Charger l'image uniquement quand la thumbnail est dans le viewport
useEffect(() => {
if (!isInViewport) return;
try { try {
const url = getThumbnailUrl(pageNumber); const url = getThumbnailUrl(pageNumber);
setImageUrl(url); setImageUrl(url);
@@ -36,7 +76,7 @@ export const Thumbnail = forwardRef<HTMLButtonElement, ThumbnailProps>(
setHasError(true); setHasError(true);
setIsLoading(false); setIsLoading(false);
} }
}, [pageNumber, getThumbnailUrl, loadedThumbnails, resetLoadingState]); }, [pageNumber, getThumbnailUrl, loadedThumbnails, resetLoadingState, isVisible, isInViewport]);
const handleImageLoad = useCallback(() => { const handleImageLoad = useCallback(() => {
setIsLoading(false); setIsLoading(false);
@@ -65,7 +105,14 @@ export const Thumbnail = forwardRef<HTMLButtonElement, ThumbnailProps>(
return ( return (
<button <button
ref={ref} ref={(node) => {
thumbnailRef.current = node;
if (typeof ref === "function") {
ref(node);
} else if (ref) {
ref.current = node;
}
}}
data-page={pageNumber} data-page={pageNumber}
id={`thumbnail-${pageNumber}`} id={`thumbnail-${pageNumber}`}
onClick={() => onPageChange(pageNumber)} onClick={() => onPageChange(pageNumber)}