mirror of
https://github.com/Qortal/qapp-core.git
synced 2025-06-14 17:41:20 +00:00
added custom expiration to caches
This commit is contained in:
parent
52f1d570a6
commit
dcfe746b5b
@ -1,7 +1,7 @@
|
||||
import React, { useRef, useEffect, useState, useCallback } from "react";
|
||||
import React, { useEffect, useState, useCallback } from "react";
|
||||
import DynamicGrid from "./DynamicGrid";
|
||||
import LazyLoad from "../../common/LazyLoad";
|
||||
import { ListItem } from "../../state/cache";
|
||||
import { ListItem, useCacheStore } from "../../state/cache";
|
||||
import { QortalMetadata } from "../../types/interfaces/resources";
|
||||
import { ListItemWrapper } from "./ResourceListDisplay";
|
||||
|
||||
@ -15,6 +15,7 @@ interface HorizontalPaginatedListProps {
|
||||
gap?: number;
|
||||
isLoading?: boolean;
|
||||
onSeenLastItem?: (listItem: ListItem) => void;
|
||||
|
||||
}
|
||||
|
||||
export const HorizontalPaginatedList = ({
|
||||
@ -27,26 +28,25 @@ export const HorizontalPaginatedList = ({
|
||||
gap,
|
||||
isLoading,
|
||||
onSeenLastItem,
|
||||
|
||||
}: HorizontalPaginatedListProps) => {
|
||||
const listRef = useRef<HTMLDivElement | null>(null);
|
||||
const [displayedItems, setDisplayedItems] = useState(items);
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
setDisplayedItems(items);
|
||||
}, [items]);
|
||||
|
||||
const preserveScroll = useCallback((updateFunction: () => void) => {
|
||||
const container = listRef.current;
|
||||
if (!container) return;
|
||||
|
||||
const previousScrollLeft = container.scrollLeft;
|
||||
const previousScrollWidth = container.scrollWidth;
|
||||
const previousScrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft;
|
||||
const previousScrollWidth = document.documentElement.scrollWidth || document.body.scrollWidth;
|
||||
|
||||
updateFunction(); // Perform the update (fetch new data, remove old)
|
||||
|
||||
requestAnimationFrame(() => {
|
||||
const newScrollWidth = container.scrollWidth;
|
||||
container.scrollLeft = previousScrollLeft - (previousScrollWidth - newScrollWidth);
|
||||
const newScrollWidth = document.documentElement.scrollWidth || document.body.scrollWidth;
|
||||
document.documentElement.scrollLeft = document.body.scrollLeft =
|
||||
previousScrollLeft - (previousScrollWidth - newScrollWidth);
|
||||
});
|
||||
}, []);
|
||||
|
||||
@ -60,28 +60,23 @@ export const HorizontalPaginatedList = ({
|
||||
}, [displayedItems, maxItems, preserveScroll]);
|
||||
|
||||
useEffect(() => {
|
||||
const container = listRef.current;
|
||||
if (!container) return;
|
||||
|
||||
const handleScroll = () => {
|
||||
if (
|
||||
container.scrollLeft + container.clientWidth >= container.scrollWidth - 10 &&
|
||||
!isLoading
|
||||
) {
|
||||
const scrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft;
|
||||
const clientWidth = document.documentElement.clientWidth || document.body.clientWidth;
|
||||
const scrollWidth = document.documentElement.scrollWidth || document.body.scrollWidth;
|
||||
|
||||
if (scrollLeft + clientWidth >= scrollWidth - 10 && !isLoading) {
|
||||
onLoadMore();
|
||||
}
|
||||
};
|
||||
|
||||
container.addEventListener("scroll", handleScroll);
|
||||
return () => container.removeEventListener("scroll", handleScroll);
|
||||
window.addEventListener("scroll", handleScroll);
|
||||
return () => window.removeEventListener("scroll", handleScroll);
|
||||
}, [onLoadMore, isLoading]);
|
||||
|
||||
return (
|
||||
<div ref={listRef} style={{
|
||||
overflow: 'auto', width: '100%', display: 'flex', flexGrow: 1
|
||||
}}>
|
||||
<div style={{ overflow: "auto", width: "100%", display: "flex", flexGrow: 1 }}>
|
||||
<DynamicGrid
|
||||
|
||||
minItemWidth={minItemWidth}
|
||||
gap={gap}
|
||||
items={displayedItems.map((item, index) => (
|
||||
@ -95,19 +90,17 @@ export const HorizontalPaginatedList = ({
|
||||
</React.Fragment>
|
||||
))}
|
||||
>
|
||||
{!isLoading && displayedItems.length > 0 && (
|
||||
<LazyLoad
|
||||
onLoadMore={() => {
|
||||
onLoadMore();
|
||||
if (onSeenLastItem) {
|
||||
// onSeenLastItem(displayedItems[displayedItems.length - 1]);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</DynamicGrid>
|
||||
|
||||
|
||||
{!isLoading && displayedItems.length > 0 && (
|
||||
<LazyLoad
|
||||
onLoadMore={() => {
|
||||
onLoadMore();
|
||||
if (onSeenLastItem) {
|
||||
// onSeenLastItem(displayedItems[displayedItems.length - 1]);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</DynamicGrid>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
};
|
||||
|
@ -23,6 +23,7 @@ import DynamicGrid from "./DynamicGrid";
|
||||
import LazyLoad from "../../common/LazyLoad";
|
||||
import { useListStore } from "../../state/lists";
|
||||
import { useScrollTracker } from "../../common/useScrollTracker";
|
||||
import { HorizontalPaginatedList } from "./HorizontalPaginationList";
|
||||
type Direction = "VERTICAL" | "HORIZONTAL";
|
||||
|
||||
interface ResourceListStyles {
|
||||
@ -54,6 +55,8 @@ interface BaseProps {
|
||||
onSeenLastItem?: (listItem: QortalMetadata) => void;
|
||||
listName: string,
|
||||
children?: React.ReactNode;
|
||||
searchCacheDuration?: number
|
||||
resourceCacheDuration?: number
|
||||
}
|
||||
|
||||
// ✅ Restrict `direction` only when `disableVirtualization = false`
|
||||
@ -82,6 +85,8 @@ export const MemorizedComponent = ({
|
||||
direction = "VERTICAL",
|
||||
onSeenLastItem,
|
||||
listName,
|
||||
searchCacheDuration,
|
||||
resourceCacheDuration
|
||||
}: PropsResourceListDisplay) => {
|
||||
const { fetchResources } = useResources();
|
||||
const { getTemporaryResources, filterOutDeletedResources } = useCacheStore();
|
||||
@ -93,12 +98,6 @@ export const MemorizedComponent = ({
|
||||
const list = useListStore().getListByName(listName)
|
||||
const isListExpired = useCacheStore().isListExpired(listName)
|
||||
const initialized = useRef(false)
|
||||
useScrollTracker(listName);
|
||||
|
||||
const listToDisplay = useMemo(()=> {
|
||||
return filterOutDeletedResources([...getTemporaryResources(listName), ...list])
|
||||
}, [list, listName, filterOutDeletedResources, getTemporaryResources])
|
||||
|
||||
|
||||
const getResourceList = useCallback(async () => {
|
||||
try {
|
||||
@ -122,6 +121,37 @@ export const MemorizedComponent = ({
|
||||
}
|
||||
}, [memoizedParams, fetchResources]); // Added dependencies for re-fetching
|
||||
|
||||
useEffect(() => {
|
||||
if(initialized.current) return
|
||||
initialized.current = true
|
||||
if(!isListExpired) return
|
||||
|
||||
sessionStorage.removeItem(`scroll-position-${listName}`);
|
||||
getResourceList();
|
||||
}, [getResourceList, isListExpired]); // Runs when dependencies change
|
||||
|
||||
useScrollTracker(listName);
|
||||
|
||||
const setSearchCacheExpiryDuration = useCacheStore().setSearchCacheExpiryDuration
|
||||
const setResourceCacheExpiryDuration = useCacheStore().setResourceCacheExpiryDuration
|
||||
useEffect(()=> {
|
||||
if(searchCacheDuration){
|
||||
setSearchCacheExpiryDuration(searchCacheDuration)
|
||||
}
|
||||
}, [])
|
||||
useEffect(()=> {
|
||||
if(resourceCacheDuration){
|
||||
setResourceCacheExpiryDuration(resourceCacheDuration)
|
||||
}
|
||||
}, [])
|
||||
|
||||
const listToDisplay = useMemo(()=> {
|
||||
return filterOutDeletedResources([...getTemporaryResources(listName), ...list])
|
||||
}, [list, listName, filterOutDeletedResources, getTemporaryResources])
|
||||
|
||||
|
||||
|
||||
|
||||
const getResourceMoreList = useCallback(async () => {
|
||||
try {
|
||||
// setIsLoading(true);
|
||||
@ -137,13 +167,7 @@ export const MemorizedComponent = ({
|
||||
}
|
||||
}, [memoizedParams, listName, list]);
|
||||
|
||||
useEffect(() => {
|
||||
if(initialized.current) return
|
||||
initialized.current = true
|
||||
if(!isListExpired) return
|
||||
sessionStorage.removeItem(`scroll-position-${listName}`);
|
||||
getResourceList();
|
||||
}, [getResourceList, isListExpired]); // Runs when dependencies change
|
||||
|
||||
|
||||
const disabledVirutalizationStyles: CSSProperties = useMemo(() => {
|
||||
if (styles?.disabledVirutalizationStyles?.parentContainer)
|
||||
@ -212,7 +236,6 @@ export const MemorizedComponent = ({
|
||||
)}
|
||||
{disableVirtualization && direction === "HORIZONTAL" && (
|
||||
<>
|
||||
|
||||
<DynamicGrid
|
||||
minItemWidth={styles?.horizontalStyles?.minItemWidth}
|
||||
gap={styles?.gap}
|
||||
|
@ -249,7 +249,7 @@ export const useResources = () => {
|
||||
fetchIndividualPublish,
|
||||
addNewResources,
|
||||
updateNewResources,
|
||||
deleteProduct
|
||||
deleteProduct,
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -65,14 +65,21 @@ interface CacheState {
|
||||
markResourceAsDeleted: (item: QortalMetadata) => void;
|
||||
filterOutDeletedResources: (items: QortalMetadata[]) => QortalMetadata[];
|
||||
isListExpired: (listName: string)=> boolean
|
||||
searchCacheExpiryDuration: number;
|
||||
resourceCacheExpiryDuration: number;
|
||||
setSearchCacheExpiryDuration: (duration: number) => void;
|
||||
setResourceCacheExpiryDuration: (duration: number)=> void;
|
||||
}
|
||||
|
||||
export const useCacheStore = create<CacheState>
|
||||
((set, get) => ({
|
||||
searchCacheExpiryDuration: 5 * 60 * 1000,
|
||||
resourceCacheExpiryDuration: 30 * 60 * 1000,
|
||||
resourceCache: {},
|
||||
searchCache: {},
|
||||
deletedResources: {},
|
||||
|
||||
setSearchCacheExpiryDuration: (duration) => set({ searchCacheExpiryDuration: duration }),
|
||||
setResourceCacheExpiryDuration: (duration) => set({ resourceCacheExpiryDuration: duration }),
|
||||
getResourceCache: (id, ignoreExpire) => {
|
||||
const cache = get().resourceCache[id];
|
||||
if (cache) {
|
||||
@ -91,7 +98,7 @@ export const useCacheStore = create<CacheState>
|
||||
|
||||
setResourceCache: (id, data, customExpiry) =>
|
||||
set((state) => {
|
||||
const expiry = Date.now() + (customExpiry || 30 * 60 * 1000); // 30 mins
|
||||
const expiry = Date.now() + (customExpiry || get().resourceCacheExpiryDuration);
|
||||
return {
|
||||
resourceCache: {
|
||||
...state.resourceCache,
|
||||
@ -100,24 +107,25 @@ export const useCacheStore = create<CacheState>
|
||||
};
|
||||
}),
|
||||
|
||||
setSearchCache: (listName, searchTerm, data, customExpiry) =>
|
||||
set((state) => {
|
||||
const expiry = Date.now() + (customExpiry || 5 * 60 * 1000); // 5 mins
|
||||
|
||||
return {
|
||||
searchCache: {
|
||||
...state.searchCache,
|
||||
[listName]: {
|
||||
searches: {
|
||||
...(state.searchCache[listName]?.searches || {}),
|
||||
[searchTerm]: data,
|
||||
setSearchCache: (listName, searchTerm, data, customExpiry) =>
|
||||
set((state) => {
|
||||
const expiry = Date.now() + (customExpiry || get().searchCacheExpiryDuration);
|
||||
|
||||
return {
|
||||
searchCache: {
|
||||
...state.searchCache,
|
||||
[listName]: {
|
||||
searches: {
|
||||
...(state.searchCache[listName]?.searches || {}),
|
||||
[searchTerm]: data,
|
||||
},
|
||||
temporaryNewResources: state.searchCache[listName]?.temporaryNewResources || [],
|
||||
expiry,
|
||||
},
|
||||
temporaryNewResources: state.searchCache[listName]?.temporaryNewResources || [],
|
||||
expiry,
|
||||
},
|
||||
},
|
||||
};
|
||||
}),
|
||||
};
|
||||
}),
|
||||
|
||||
|
||||
getSearchCache: (listName, searchTerm) => {
|
||||
const cache = get().searchCache[listName];
|
||||
|
Loading…
x
Reference in New Issue
Block a user