From e78a46ab242196442f6bef6450d210ff03a22fcf Mon Sep 17 00:00:00 2001 From: jeffvli Date: Mon, 24 Nov 2025 22:46:23 -0800 Subject: [PATCH] optimize list refresh functions --- .../helpers/item-list-infinite-loader.ts | 62 ++++++++++++++++--- .../helpers/item-list-paginated-loader.ts | 21 +++++-- .../components/album-list-paginated-grid.tsx | 1 + .../components/album-list-paginated-table.tsx | 1 + .../album-artist-list-paginated-grid.tsx | 1 + .../album-artist-list-paginated-table.tsx | 1 + .../components/artist-list-paginated-grid.tsx | 1 + .../artist-list-paginated-table.tsx | 1 + .../components/genre-list-paginated-grid.tsx | 1 + .../components/genre-list-paginated-table.tsx | 1 + .../genres/routes/genre-detail-route.tsx | 5 +- .../playlist-list-paginated-grid.tsx | 1 + .../playlist-list-paginated-table.tsx | 1 + .../components/song-list-paginated-grid.tsx | 1 + .../components/song-list-paginated-table.tsx | 1 + 15 files changed, 84 insertions(+), 16 deletions(-) diff --git a/src/renderer/components/item-list/helpers/item-list-infinite-loader.ts b/src/renderer/components/item-list/helpers/item-list-infinite-loader.ts index a4a5921a0..461dbf9d9 100644 --- a/src/renderer/components/item-list/helpers/item-list-infinite-loader.ts +++ b/src/renderer/components/item-list/helpers/item-list-infinite-loader.ts @@ -5,7 +5,7 @@ import { UseSuspenseQueryOptions, } from '@tanstack/react-query'; import throttle from 'lodash/throttle'; -import { useCallback, useEffect, useMemo } from 'react'; +import { useCallback, useEffect, useMemo, useRef } from 'react'; import { queryKeys } from '/@/renderer/api/query-keys'; import { useListContext } from '/@/renderer/context/list-context'; @@ -61,6 +61,8 @@ export const useItemListInfiniteLoader = ({ serverId, }: UseItemListInfiniteLoaderProps) => { const queryClient = useQueryClient(); + const lastFetchedPageRef = useRef(-1); + const currentVisibleRangeRef = useRef(null); const { data: totalItemCount } = useSuspenseQuery(listCountQuery); @@ -88,6 +90,8 @@ export const useItemListInfiniteLoader = ({ pagesLoaded: {}, }; }); + lastFetchedPageRef.current = -1; + currentVisibleRangeRef.current = null; }, [query, queryClient, dataQueryKey]); const { data } = useQuery<{ data: unknown[]; pagesLoaded: Record }>({ @@ -144,12 +148,18 @@ export const useItemListInfiniteLoader = ({ }; }, ); + + // Track the last fetched page + lastFetchedPageRef.current = Math.max(lastFetchedPageRef.current, pageNumber); }, [itemsPerPage, query, queryClient, serverId, dataQueryKey, listQueryFn, itemType], ); const onRangeChangedBase = useCallback( async (range: { startIndex: number; stopIndex: number }) => { + // Track the current visible range + currentVisibleRangeRef.current = range; + const pageNumber = Math.floor(range.startIndex / itemsPerPage); const currentData = queryClient.getQueryData<{ @@ -204,18 +214,54 @@ export const useItemListInfiniteLoader = ({ const refresh = useCallback( async (force?: boolean) => { + // Invalidate all queries to ensure fresh data await queryClient.invalidateQueries(); - if (force) { - await queryClient.setQueryData(dataQueryKey, getInitialData(totalItemCount)); + // Reset the infinite list data + const currentData = queryClient.getQueryData<{ + data: unknown[]; + pagesLoaded: Record; + }>(dataQueryKey); + + if (force || currentData) { + // Reset data to initial state and clear all loaded pages + await queryClient.setQueryData(dataQueryKey, (oldData: any) => { + if (!oldData) return getInitialData(totalItemCount); + return { + ...oldData, + data: Array.from({ length: totalItemCount }, () => undefined), + pagesLoaded: {}, + }; + }); + lastFetchedPageRef.current = -1; } - // await onRangeChanged({ - // endIndex: currentPageRef.current * itemsPerPage, - // startIndex: currentPageRef.current * itemsPerPage, - // }); + // Add a delay to make the refresh visually clear + await new Promise((resolve) => setTimeout(resolve, 150)); + + // Determine which page to refetch based on current visible range + let pageToFetch = 0; + if (currentVisibleRangeRef.current) { + // Calculate the page from the current visible range + pageToFetch = Math.floor(currentVisibleRangeRef.current.startIndex / itemsPerPage); + } else if (lastFetchedPageRef.current >= 0) { + // Fallback to last fetched page if no visible range is tracked + pageToFetch = lastFetchedPageRef.current; + } + + // Refetch the current page + await fetchPage(pageToFetch); + + // Trigger range changed to ensure adjacent pages are prefetched if needed + const startIndex = pageToFetch * itemsPerPage; + const stopIndex = Math.min((pageToFetch + 1) * itemsPerPage, totalItemCount); + + await onRangeChangedBase({ + startIndex, + stopIndex, + }); }, - [queryClient, totalItemCount, dataQueryKey], + [queryClient, itemsPerPage, onRangeChangedBase, dataQueryKey, totalItemCount, fetchPage], ); const updateItems = useCallback( diff --git a/src/renderer/components/item-list/helpers/item-list-paginated-loader.ts b/src/renderer/components/item-list/helpers/item-list-paginated-loader.ts index 0ca98b5c3..56e508e30 100644 --- a/src/renderer/components/item-list/helpers/item-list-paginated-loader.ts +++ b/src/renderer/components/item-list/helpers/item-list-paginated-loader.ts @@ -98,9 +98,22 @@ export const useItemListPaginatedLoader = ({ staleTime: 1000 * 15, }); - const refresh = useCallback(() => { - return queryRefetch(); - }, [queryRefetch]); + const refresh = useCallback( + async (force?: boolean) => { + const queryKey = queryKeys[getQueryKeyName(itemType)].list(serverId, queryParams); + + await queryClient.invalidateQueries(); + + if (force) { + queryClient.setQueryData(queryKey, { + items: getInitialData(itemsPerPage), + }); + } + + return queryRefetch(); + }, + [queryClient, queryRefetch, queryParams, serverId, itemType, itemsPerPage], + ); const updateItems = useCallback( (indexes: number[], value: object) => { @@ -140,7 +153,7 @@ export const useItemListPaginatedLoader = ({ return; } - return refresh(); + return refresh(true); }; const handleFavorite = (payload: UserFavoriteEventPayload) => { diff --git a/src/renderer/features/albums/components/album-list-paginated-grid.tsx b/src/renderer/features/albums/components/album-list-paginated-grid.tsx index 290bbb6c7..3c34b4440 100644 --- a/src/renderer/features/albums/components/album-list-paginated-grid.tsx +++ b/src/renderer/features/albums/components/album-list-paginated-grid.tsx @@ -46,6 +46,7 @@ export const AlbumListPaginatedGrid = forwardRef { return genres?.items.find((g) => g.id === genreId)?.name || '—'; }, [genreId, genres]); - const location = useLocation(); - console.log('location', location.pathname); - return ( diff --git a/src/renderer/features/playlists/components/playlist-list-paginated-grid.tsx b/src/renderer/features/playlists/components/playlist-list-paginated-grid.tsx index bfe75b8c7..5fa723053 100644 --- a/src/renderer/features/playlists/components/playlist-list-paginated-grid.tsx +++ b/src/renderer/features/playlists/components/playlist-list-paginated-grid.tsx @@ -46,6 +46,7 @@ export const PlaylistListPaginatedGrid = forwardRef const { data, pageCount, totalItemCount } = useItemListPaginatedLoader({ currentPage, + eventKey: ItemListKey.SONG, itemsPerPage, itemType: LibraryItem.SONG, listCountQuery, diff --git a/src/renderer/features/songs/components/song-list-paginated-table.tsx b/src/renderer/features/songs/components/song-list-paginated-table.tsx index 5be4bf6dd..a7186ddba 100644 --- a/src/renderer/features/songs/components/song-list-paginated-table.tsx +++ b/src/renderer/features/songs/components/song-list-paginated-table.tsx @@ -49,6 +49,7 @@ export const SongListPaginatedTable = forwardRef