mirror of
https://github.com/jeffvli/feishin.git
synced 2026-06-10 22:32:17 +02:00
fix: preserve infinite list cache on component remount (fixes random sort reshuffling) (#2097)
* fix: preserve infinite list cache on component remount When browsing with random sort, navigating to a detail view and coming back would reshuffle the list. This happens because the list component unmounts, losing its internal ref guard, and the reset effect re-fetches all pages — returning a new random order from the server.
This commit is contained in:
@@ -13,7 +13,7 @@ import { useListContext } from '/@/renderer/context/list-context';
|
||||
import { eventEmitter } from '/@/renderer/events/event-emitter';
|
||||
import { UserFavoriteEventPayload, UserRatingEventPayload } from '/@/renderer/events/events';
|
||||
import { getListRefreshMutationKey } from '/@/renderer/features/shared/components/list-refresh-button';
|
||||
import { LibraryItem } from '/@/shared/types/domain-types';
|
||||
import { LibraryItem, SortKeyRandom } from '/@/shared/types/domain-types';
|
||||
|
||||
export const getListQueryKeyName = (itemType: LibraryItem): string => {
|
||||
switch (itemType) {
|
||||
@@ -108,8 +108,19 @@ export const useItemListInfiniteLoader = ({
|
||||
[serverId, itemType, query],
|
||||
);
|
||||
|
||||
const isRandomSort = query?.sortBy === SortKeyRandom;
|
||||
|
||||
const fetchPage = useCallback(
|
||||
async (pageNumber: number) => {
|
||||
if (isRandomSort) {
|
||||
const existingData =
|
||||
queryClient.getQueryData<InfiniteLoaderCacheData>(dataQueryKey);
|
||||
if (existingData?.pagesLoaded?.[pageNumber]) {
|
||||
lastFetchedPageRef.current = Math.max(lastFetchedPageRef.current, pageNumber);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const startIndex = pageNumber * itemsPerPage;
|
||||
const queryParams = {
|
||||
limit: itemsPerPage,
|
||||
@@ -118,6 +129,7 @@ export const useItemListInfiniteLoader = ({
|
||||
};
|
||||
|
||||
const result = await queryClient.fetchQuery({
|
||||
gcTime: isRandomSort ? 1000 * 60 * 10 : 1000 * 15,
|
||||
queryFn: async ({ signal }) => {
|
||||
const result = await listQueryFn({
|
||||
apiClientProps: { serverId, signal },
|
||||
@@ -127,6 +139,7 @@ export const useItemListInfiniteLoader = ({
|
||||
return result;
|
||||
},
|
||||
queryKey: queryKeys[getListQueryKeyName(itemType)].list(serverId, queryParams),
|
||||
staleTime: isRandomSort ? 1000 * 60 * 10 : 1000 * 15,
|
||||
});
|
||||
|
||||
// Update the query data with the fetched page
|
||||
@@ -154,13 +167,32 @@ export const useItemListInfiniteLoader = ({
|
||||
// Track the last fetched page
|
||||
lastFetchedPageRef.current = Math.max(lastFetchedPageRef.current, pageNumber);
|
||||
},
|
||||
[itemsPerPage, query, queryClient, serverId, dataQueryKey, listQueryFn, itemType],
|
||||
[
|
||||
itemsPerPage,
|
||||
query,
|
||||
queryClient,
|
||||
serverId,
|
||||
dataQueryKey,
|
||||
listQueryFn,
|
||||
itemType,
|
||||
isRandomSort,
|
||||
],
|
||||
);
|
||||
|
||||
// Reset the loaded pages and refetch current page when the query changes
|
||||
useEffect(() => {
|
||||
const currentDataQueryKey = JSON.stringify(dataQueryKey);
|
||||
|
||||
if (isRandomSort) {
|
||||
const existingData = queryClient.getQueryData<InfiniteLoaderCacheData | undefined>(
|
||||
dataQueryKey,
|
||||
);
|
||||
if (existingData?.dataMap && existingData.dataMap.size > 0) {
|
||||
previousDataQueryKeyRef.current = currentDataQueryKey;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (previousDataQueryKeyRef.current === currentDataQueryKey || isRefetchingRef.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ import { useListContext } from '/@/renderer/context/list-context';
|
||||
import { eventEmitter } from '/@/renderer/events/event-emitter';
|
||||
import { UserFavoriteEventPayload, UserRatingEventPayload } from '/@/renderer/events/events';
|
||||
import { getListRefreshMutationKey } from '/@/renderer/features/shared/components/list-refresh-button';
|
||||
import { LibraryItem } from '/@/shared/types/domain-types';
|
||||
import { LibraryItem, SortKeyRandom } from '/@/shared/types/domain-types';
|
||||
|
||||
const getQueryKeyName = (itemType: LibraryItem): string => {
|
||||
switch (itemType) {
|
||||
@@ -76,6 +76,8 @@ export const useItemListPaginatedLoader = ({
|
||||
const fetchRange = getFetchRange(currentPage, itemsPerPage);
|
||||
const startIndex = fetchRange.startIndex;
|
||||
|
||||
const isRandomSort = query?.sortBy === SortKeyRandom;
|
||||
|
||||
const queryParams = useMemo(
|
||||
() => ({
|
||||
limit: itemsPerPage,
|
||||
@@ -86,7 +88,7 @@ export const useItemListPaginatedLoader = ({
|
||||
);
|
||||
|
||||
const { data } = useQuery({
|
||||
gcTime: 1000 * 15,
|
||||
gcTime: isRandomSort ? 1000 * 60 * 10 : 1000 * 15,
|
||||
placeholderData: { items: getInitialData(itemsPerPage) },
|
||||
queryFn: async ({ signal }) => {
|
||||
const result = await listQueryFn({
|
||||
@@ -97,7 +99,7 @@ export const useItemListPaginatedLoader = ({
|
||||
return result;
|
||||
},
|
||||
queryKey: queryKeys[getQueryKeyName(itemType)].list(serverId, queryParams),
|
||||
staleTime: 1000 * 15,
|
||||
staleTime: isRandomSort ? 1000 * 60 * 10 : 1000 * 15,
|
||||
});
|
||||
|
||||
const refreshMutation = useMutation({
|
||||
|
||||
@@ -465,6 +465,8 @@ export const tagListSortMap: TagListSortMap = {
|
||||
},
|
||||
};
|
||||
|
||||
export const SortKeyRandom = 'random';
|
||||
|
||||
export enum AlbumListSort {
|
||||
ALBUM_ARTIST = 'albumArtist',
|
||||
ARTIST = 'artist',
|
||||
@@ -476,7 +478,7 @@ export enum AlbumListSort {
|
||||
ID = 'id',
|
||||
NAME = 'name',
|
||||
PLAY_COUNT = 'playCount',
|
||||
RANDOM = 'random',
|
||||
RANDOM = SortKeyRandom,
|
||||
RATING = 'rating',
|
||||
RECENTLY_ADDED = 'recentlyAdded',
|
||||
RECENTLY_PLAYED = 'recentlyPlayed',
|
||||
@@ -598,7 +600,7 @@ export enum SongListSort {
|
||||
ID = 'id',
|
||||
NAME = 'name',
|
||||
PLAY_COUNT = 'playCount',
|
||||
RANDOM = 'random',
|
||||
RANDOM = SortKeyRandom,
|
||||
RATING = 'rating',
|
||||
RECENTLY_ADDED = 'recentlyAdded',
|
||||
RECENTLY_PLAYED = 'recentlyPlayed',
|
||||
@@ -725,7 +727,7 @@ export enum AlbumArtistListSort {
|
||||
FAVORITED = 'favorited',
|
||||
NAME = 'name',
|
||||
PLAY_COUNT = 'playCount',
|
||||
RANDOM = 'random',
|
||||
RANDOM = SortKeyRandom,
|
||||
RATING = 'rating',
|
||||
RECENTLY_ADDED = 'recentlyAdded',
|
||||
RELEASE_DATE = 'releaseDate',
|
||||
@@ -814,7 +816,7 @@ export enum ArtistListSort {
|
||||
FAVORITED = 'favorited',
|
||||
NAME = 'name',
|
||||
PLAY_COUNT = 'playCount',
|
||||
RANDOM = 'random',
|
||||
RANDOM = SortKeyRandom,
|
||||
RATING = 'rating',
|
||||
RECENTLY_ADDED = 'recentlyAdded',
|
||||
RELEASE_DATE = 'releaseDate',
|
||||
|
||||
Reference in New Issue
Block a user