fix scrollto

This commit is contained in:
PhilReact 2025-06-04 01:12:54 +03:00
parent 6105a36ea2
commit d0c871d22b
6 changed files with 53 additions and 33 deletions

View File

@ -19,7 +19,7 @@ interface PropsVirtualizedList {
}
export const VirtualizedList = ({ list, children, onSeenLastItem, listName }: PropsVirtualizedList) => {
const parentRef = useRef(null);
useScrollTrackerRef(listName, parentRef)
useScrollTrackerRef(listName, list?.length > 0, parentRef)
const rowVirtualizer = useVirtualizer({
count: list.length,

View File

@ -26,10 +26,11 @@ export const useScrollTracker = (listName: string, hasList: boolean, disableScro
};
window.addEventListener("scroll", handleScroll);
return () => {
sessionStorage.setItem(SCROLL_KEY, scrollPositionRef.current.toString());
window.removeEventListener("scroll", handleScroll);
if(!disableScrollTracker){
sessionStorage.setItem(SCROLL_KEY, scrollPositionRef.current.toString());
window.removeEventListener("scroll", handleScroll);
}
};
}, [listName, hasList, disableScrollTracker]);

View File

@ -1,30 +1,49 @@
import { useEffect } from "react";
import { useEffect, useRef, useState } from "react";
export const useScrollTrackerRef = (listName: string, ref: React.RefObject<HTMLElement | null>) => {
export const useScrollTrackerRef = (listName: string, hasList: boolean, scrollerRef: React.RefObject<HTMLElement | null> | undefined) => {
const [hasMounted, setHasMounted] = useState(false)
const hasScrollRef = useRef(false)
useEffect(() => {
if (!listName || !ref.current) return;
if (!listName || !scrollerRef?.current || !hasMounted) return;
const SCROLL_KEY = `scroll-position-${listName}`;
const handleScroll = () => {
if(!scrollerRef.current) return
sessionStorage.setItem(SCROLL_KEY, scrollerRef.current.scrollTop.toString());
};
scrollerRef.current.addEventListener("scroll", handleScroll);
return () => {
if (scrollerRef.current) {
scrollerRef.current.removeEventListener("scroll", handleScroll);
}
};
}, [listName, hasMounted]);
useEffect(() => {
if (!listName || !hasList || hasScrollRef.current || !scrollerRef?.current) return;
const SCROLL_KEY = `scroll-position-${listName}`;
const savedPosition = sessionStorage.getItem(SCROLL_KEY);
const attemptScrollRestore = () => {
const el = scrollerRef.current;
const saved = parseInt(savedPosition || '0', 10);
if (!el) return;
if (el.scrollHeight > el.clientHeight && saved <= el.scrollHeight - el.clientHeight) {
if (savedPosition && ref.current) {
ref.current.scrollTop = parseInt(savedPosition, 10);
}
setTimeout(() => {
el.scrollTop = saved;
}, 200);
setHasMounted(true)
hasScrollRef.current = true;
} else {
requestAnimationFrame(attemptScrollRestore);
}
const handleScroll = () => {
if (ref.current) {
sessionStorage.setItem(SCROLL_KEY, ref.current.scrollTop.toString());
}
};
ref.current.addEventListener("scroll", handleScroll);
return () => {
if (ref.current) {
ref.current.removeEventListener("scroll", handleScroll);
}
};
}, [listName, ref]);
requestAnimationFrame(attemptScrollRestore);
}, [listName, hasList]);
};

View File

@ -24,6 +24,7 @@ import { HorizontalPaginatedList } from "./HorizontalPaginationList";
import { VerticalPaginatedList } from "./VerticalPaginationList";
import { useIdentifiers } from "../../hooks/useIdentifiers";
import { useGlobal } from "../../context/GlobalProvider";
import { useScrollTrackerRef } from "../../common/useScrollTrackerRef";
type Direction = "VERTICAL" | "HORIZONTAL";
interface ResourceListStyles {
@ -82,6 +83,7 @@ interface BaseProps {
}
onNewData?: (hasNewData: boolean) => void;
ref?: any
scrollerRef?: React.RefObject<HTMLElement | null>
}
// ✅ Restrict `direction` only when `disableVirtualization = false`
@ -121,7 +123,8 @@ export const MemorizedComponent = ({
onResults,
searchNewData,
onNewData,
ref
ref,
scrollerRef
}: PropsResourceListDisplay) => {
const {identifierOperations, lists} = useGlobal()
const memoizedParams = useMemo(() => JSON.stringify(search), [search]);
@ -271,22 +274,19 @@ const addItems = useListStore((s) => s.addItems);
const parsedParams = {...(JSON.parse(memoizedParamsRef.current))};
parsedParams.identifier = generatedIdentifier
const stringedParams = JSON.stringify(parsedParams)
if(stringedParams === isListExpiredRef.current && !initialized.current){
if(stringedParams === isListExpiredRef.current){
setIsLoading(false)
initialized.current = true
return
}
}
sessionStorage.removeItem(`scroll-position-${listName}`);
prevGeneratedIdentifierRef.current = generatedIdentifier
getResourceList();
}, [getResourceList, generatedIdentifier]); // Runs when dependencies change
const {elementRef} = useScrollTracker(listName, list?.length > 0, disableScrollTracker);
const {elementRef} = useScrollTracker(listName, list?.length > 0, scrollerRef ? true : !disableVirtualization ? true : disableScrollTracker);
useScrollTrackerRef(listName, list?.length > 0, scrollerRef)
const setSearchCacheExpiryDuration = useCacheStore((s) => s.setSearchCacheExpiryDuration);
const setResourceCacheExpiryDuration = useCacheStore((s) => s.setResourceCacheExpiryDuration);

View File

@ -240,7 +240,7 @@ export const useResources = (retryAttempts: number = 2) => {
if (!lastCreated) break;
}
setSearchCache(listName, cacheKey, filteredResults, JSON.stringify(params));
setSearchCache(listName, cacheKey, filteredResults, cancelRequests ? JSON.stringify(params) : null);
fetchDataFromResults(filteredResults, returnType);
return filteredResults;

View File

@ -56,7 +56,7 @@ interface CacheState {
// Search cache actions
setResourceCache: (id: string, data: ListItem | false | null, customExpiry?: number) => void;
setSearchCache: (listName: string, searchTerm: string, data: QortalMetadata[], searchParamsStringified: string, customExpiry?: number) => void;
setSearchCache: (listName: string, searchTerm: string, data: QortalMetadata[], searchParamsStringified: string | null, customExpiry?: number) => void;
getSearchCache: (listName: string, searchTerm: string) => QortalMetadata[] | null;
clearExpiredCache: () => void;
getResourceCache: (id: string, ignoreExpire?: boolean) => ListItem | false | null;
@ -122,7 +122,7 @@ export const useCacheStore = create<CacheState>
},
temporaryNewResources: state.searchCache[listName]?.temporaryNewResources || [],
expiry,
searchParamsStringified
searchParamsStringified: searchParamsStringified === null ? state.searchCache[listName]?.searchParamsStringified : searchParamsStringified
},
},
};