optimize list refresh functions

This commit is contained in:
jeffvli
2025-11-24 22:46:23 -08:00
parent d3132ad570
commit e78a46ab24
15 changed files with 84 additions and 16 deletions
@@ -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<number>(-1);
const currentVisibleRangeRef = useRef<null | { startIndex: number; stopIndex: number }>(null);
const { data: totalItemCount } = useSuspenseQuery<number, any, number, any>(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<string, boolean> }>({
@@ -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<string, boolean>;
}>(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(
@@ -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) => {
@@ -46,6 +46,7 @@ export const AlbumListPaginatedGrid = forwardRef<any, AlbumListPaginatedGridProp
const { data, pageCount, totalItemCount } = useItemListPaginatedLoader({
currentPage,
eventKey: ItemListKey.ALBUM,
itemsPerPage,
itemType: LibraryItem.ALBUM,
listCountQuery,
@@ -54,6 +54,7 @@ export const AlbumListPaginatedTable = forwardRef<any, AlbumListPaginatedTablePr
const { data, pageCount, totalItemCount } = useItemListPaginatedLoader({
currentPage,
eventKey: ItemListKey.ALBUM,
itemsPerPage,
itemType: LibraryItem.ALBUM,
listCountQuery,
@@ -47,6 +47,7 @@ export const AlbumArtistListPaginatedGrid = forwardRef<any, AlbumArtistListPagin
const { data, pageCount, totalItemCount } = useItemListPaginatedLoader({
currentPage,
eventKey: ItemListKey.ALBUM_ARTIST,
itemsPerPage,
itemType: LibraryItem.ALBUM_ARTIST,
listCountQuery,
@@ -55,6 +55,7 @@ export const AlbumArtistListPaginatedTable = forwardRef<any, AlbumArtistListPagi
const { data, pageCount, totalItemCount } = useItemListPaginatedLoader({
currentPage,
eventKey: ItemListKey.ALBUM_ARTIST,
itemsPerPage,
itemType: LibraryItem.ALBUM_ARTIST,
listCountQuery,
@@ -46,6 +46,7 @@ export const ArtistListPaginatedGrid = forwardRef<any, ArtistListPaginatedGridPr
const { data, pageCount, totalItemCount } = useItemListPaginatedLoader({
currentPage,
eventKey: ItemListKey.ARTIST,
itemsPerPage,
itemType: LibraryItem.ARTIST,
listCountQuery,
@@ -54,6 +54,7 @@ export const ArtistListPaginatedTable = forwardRef<any, ArtistListPaginatedTable
const { data, pageCount, totalItemCount } = useItemListPaginatedLoader({
currentPage,
eventKey: ItemListKey.ARTIST,
itemsPerPage,
itemType: LibraryItem.ARTIST,
listCountQuery,
@@ -46,6 +46,7 @@ export const GenreListPaginatedGrid = forwardRef<any, GenreListPaginatedGridProp
const { data, pageCount, totalItemCount } = useItemListPaginatedLoader({
currentPage,
eventKey: ItemListKey.GENRE,
itemsPerPage,
itemType: LibraryItem.GENRE,
listCountQuery,
@@ -54,6 +54,7 @@ export const GenreListPaginatedTable = forwardRef<any, GenreListPaginatedTablePr
const { data, pageCount, totalItemCount } = useItemListPaginatedLoader({
currentPage,
eventKey: ItemListKey.GENRE,
itemsPerPage,
itemType: LibraryItem.GENRE,
listCountQuery,
@@ -1,5 +1,5 @@
import { useMemo, useState } from 'react';
import { useLocation, useParams } from 'react-router';
import { useParams } from 'react-router';
import { ListContext } from '/@/renderer/context/list-context';
import { useGenreList } from '/@/renderer/features/genres/api/genres-api';
@@ -30,9 +30,6 @@ const GenreDetailRoute = () => {
return genres?.items.find((g) => g.id === genreId)?.name || '—';
}, [genreId, genres]);
const location = useLocation();
console.log('location', location.pathname);
return (
<AnimatedPage>
<ListContext.Provider value={providerValue}>
@@ -46,6 +46,7 @@ export const PlaylistListPaginatedGrid = forwardRef<any, PlaylistListPaginatedGr
const { data, pageCount, totalItemCount } = useItemListPaginatedLoader({
currentPage,
eventKey: ItemListKey.PLAYLIST,
itemsPerPage,
itemType: LibraryItem.PLAYLIST,
listCountQuery,
@@ -54,6 +54,7 @@ export const PlaylistListPaginatedTable = forwardRef<any, PlaylistListPaginatedT
const { data, pageCount, totalItemCount } = useItemListPaginatedLoader({
currentPage,
eventKey: ItemListKey.PLAYLIST,
itemsPerPage,
itemType: LibraryItem.PLAYLIST,
listCountQuery,
@@ -39,6 +39,7 @@ export const SongListPaginatedGrid = forwardRef<any, SongListPaginatedGridProps>
const { data, pageCount, totalItemCount } = useItemListPaginatedLoader({
currentPage,
eventKey: ItemListKey.SONG,
itemsPerPage,
itemType: LibraryItem.SONG,
listCountQuery,
@@ -49,6 +49,7 @@ export const SongListPaginatedTable = forwardRef<any, SongListPaginatedTableProp
const { data, pageCount, totalItemCount } = useItemListPaginatedLoader({
currentPage,
eventKey: ItemListKey.SONG,
itemsPerPage,
itemType: LibraryItem.SONG,
listCountQuery,