Use global state for grid card views

- Prevent re-render when fetching already cached state
This commit is contained in:
jeffvli 2023-01-03 17:41:03 -08:00
parent 19eaf44394
commit 16433457ad
6 changed files with 93 additions and 12 deletions

View file

@ -1,12 +1,4 @@
import { import { useRef, useMemo, useCallback, forwardRef, Ref, useImperativeHandle } from 'react';
useState,
useRef,
useMemo,
useCallback,
forwardRef,
Ref,
useImperativeHandle,
} from 'react';
import debounce from 'lodash/debounce'; import debounce from 'lodash/debounce';
import type { FixedSizeListProps } from 'react-window'; import type { FixedSizeListProps } from 'react-window';
import InfiniteLoader from 'react-window-infinite-loader'; import InfiniteLoader from 'react-window-infinite-loader';
@ -25,11 +17,13 @@ interface VirtualGridProps extends Omit<FixedSizeListProps, 'children' | 'itemSi
display?: ListDisplayType; display?: ListDisplayType;
fetchFn: (options: { columnCount: number; skip: number; take: number }) => Promise<any>; fetchFn: (options: { columnCount: number; skip: number; take: number }) => Promise<any>;
handlePlayQueueAdd?: (options: PlayQueueAddOptions) => void; handlePlayQueueAdd?: (options: PlayQueueAddOptions) => void;
itemData: any[];
itemGap: number; itemGap: number;
itemSize: number; itemSize: number;
itemType: LibraryItem; itemType: LibraryItem;
minimumBatchSize?: number; minimumBatchSize?: number;
route?: CardRoute; route?: CardRoute;
setItemData: (data: any[]) => void;
} }
const constrainWidth = (width: number) => { const constrainWidth = (width: number) => {
@ -48,6 +42,8 @@ export const VirtualInfiniteGrid = forwardRef(
itemSize, itemSize,
itemType, itemType,
cardRows, cardRows,
itemData,
setItemData,
route, route,
onScroll, onScroll,
display, display,
@ -60,7 +56,6 @@ export const VirtualInfiniteGrid = forwardRef(
}: VirtualGridProps, }: VirtualGridProps,
ref: Ref<VirtualInfiniteGridRef>, ref: Ref<VirtualInfiniteGridRef>,
) => { ) => {
const [itemData, setItemData] = useState<any[]>([]);
const listRef = useRef<any>(null); const listRef = useRef<any>(null);
const loader = useRef<InfiniteLoader>(null); const loader = useRef<InfiniteLoader>(null);
@ -111,7 +106,7 @@ export const VirtualInfiniteGrid = forwardRef(
setItemData(newData); setItemData(newData);
}, },
[columnCount, fetchFn, itemData], [columnCount, fetchFn, itemData, setItemData],
); );
const debouncedLoadMoreItems = debounce(loadMoreItems, 500); const debouncedLoadMoreItems = debounce(loadMoreItems, 500);
@ -120,7 +115,7 @@ export const VirtualInfiniteGrid = forwardRef(
resetLoadMoreItemsCache: () => { resetLoadMoreItemsCache: () => {
if (loader.current) { if (loader.current) {
loader.current.resetloadMoreItemsCache(false); loader.current.resetloadMoreItemsCache(false);
setItemData(() => []); setItemData([]);
} }
}, },
scrollTo: (index: number) => { scrollTo: (index: number) => {

View file

@ -25,6 +25,7 @@ import {
useAlbumTablePagination, useAlbumTablePagination,
useSetAlbumTable, useSetAlbumTable,
useSetAlbumTablePagination, useSetAlbumTablePagination,
useAlbumListItemData,
} from '/@/renderer/store'; } from '/@/renderer/store';
import type { AgGridReact as AgGridReactType } from '@ag-grid-community/react/lib/agGridReact'; import type { AgGridReact as AgGridReactType } from '@ag-grid-community/react/lib/agGridReact';
import { import {
@ -57,6 +58,8 @@ export const AlbumListContent = ({ gridRef, tableRef }: AlbumListContentProps) =
const setPage = useSetAlbumStore(); const setPage = useSetAlbumStore();
const handlePlayQueueAdd = usePlayQueueAdd(); const handlePlayQueueAdd = usePlayQueueAdd();
const { itemData, setItemData } = useAlbumListItemData();
const pagination = useAlbumTablePagination(); const pagination = useAlbumTablePagination();
const setPagination = useSetAlbumTablePagination(); const setPagination = useSetAlbumTablePagination();
const setTable = useSetAlbumTable(); const setTable = useSetAlbumTable();
@ -319,6 +322,7 @@ export const AlbumListContent = ({ gridRef, tableRef }: AlbumListContentProps) =
height={height} height={height}
initialScrollOffset={page?.grid.scrollOffset || 0} initialScrollOffset={page?.grid.scrollOffset || 0}
itemCount={checkAlbumList?.data?.totalRecordCount || 0} itemCount={checkAlbumList?.data?.totalRecordCount || 0}
itemData={itemData}
itemGap={20} itemGap={20}
itemSize={150 + page.grid?.size} itemSize={150 + page.grid?.size}
itemType={LibraryItem.ALBUM} itemType={LibraryItem.ALBUM}
@ -327,6 +331,7 @@ export const AlbumListContent = ({ gridRef, tableRef }: AlbumListContentProps) =
route: AppRoute.LIBRARY_ALBUMS_DETAIL, route: AppRoute.LIBRARY_ALBUMS_DETAIL,
slugs: [{ idProperty: 'id', slugProperty: 'albumId' }], slugs: [{ idProperty: 'id', slugProperty: 'albumId' }],
}} }}
setItemData={setItemData}
width={width} width={width}
onScroll={handleGridScroll} onScroll={handleGridScroll}
/> />

View file

@ -23,6 +23,7 @@ import {
useSetAlbumArtistStore, useSetAlbumArtistStore,
useSetAlbumArtistTable, useSetAlbumArtistTable,
useSetAlbumArtistTablePagination, useSetAlbumArtistTablePagination,
useAlbumArtistListItemData,
} from '/@/renderer/store'; } from '/@/renderer/store';
import type { AgGridReact as AgGridReactType } from '@ag-grid-community/react/lib/agGridReact'; import type { AgGridReact as AgGridReactType } from '@ag-grid-community/react/lib/agGridReact';
import { import {
@ -56,6 +57,8 @@ export const AlbumArtistListContent = ({ gridRef, tableRef }: AlbumArtistListCon
const setPage = useSetAlbumArtistStore(); const setPage = useSetAlbumArtistStore();
const handlePlayQueueAdd = usePlayQueueAdd(); const handlePlayQueueAdd = usePlayQueueAdd();
const { itemData, setItemData } = useAlbumArtistListItemData();
const pagination = useAlbumArtistTablePagination(); const pagination = useAlbumArtistTablePagination();
const setPagination = useSetAlbumArtistTablePagination(); const setPagination = useSetAlbumArtistTablePagination();
const setTable = useSetAlbumArtistTable(); const setTable = useSetAlbumArtistTable();
@ -120,6 +123,7 @@ export const AlbumArtistListContent = ({ gridRef, tableRef }: AlbumArtistListCon
}, },
rowCount: undefined, rowCount: undefined,
}; };
params.api.setDatasource(dataSource); params.api.setDatasource(dataSource);
params.api.ensureIndexVisible(page.table.scrollOffset || 0, 'top'); params.api.ensureIndexVisible(page.table.scrollOffset || 0, 'top');
}, },
@ -298,6 +302,7 @@ export const AlbumArtistListContent = ({ gridRef, tableRef }: AlbumArtistListCon
height={height} height={height}
initialScrollOffset={page?.grid.scrollOffset || 0} initialScrollOffset={page?.grid.scrollOffset || 0}
itemCount={checkAlbumArtistList?.data?.totalRecordCount || 0} itemCount={checkAlbumArtistList?.data?.totalRecordCount || 0}
itemData={itemData}
itemGap={20} itemGap={20}
itemSize={150 + page.grid?.size} itemSize={150 + page.grid?.size}
itemType={LibraryItem.ALBUM_ARTIST} itemType={LibraryItem.ALBUM_ARTIST}
@ -306,6 +311,7 @@ export const AlbumArtistListContent = ({ gridRef, tableRef }: AlbumArtistListCon
route: AppRoute.LIBRARY_ALBUMARTISTS_DETAIL, route: AppRoute.LIBRARY_ALBUMARTISTS_DETAIL,
slugs: [{ idProperty: 'id', slugProperty: 'albumArtistId' }], slugs: [{ idProperty: 'id', slugProperty: 'albumArtistId' }],
}} }}
setItemData={setItemData}
width={width} width={width}
onScroll={handleGridScroll} onScroll={handleGridScroll}
/> />

View file

@ -0,0 +1,37 @@
import create from 'zustand';
import { devtools } from 'zustand/middleware';
import { immer } from 'zustand/middleware/immer';
export interface AlbumArtistListDataState {
itemData: any[];
}
export interface AlbumArtistListDataSlice extends AlbumArtistListDataState {
actions: {
setItemData: (data: any[]) => void;
};
}
export const useAlbumArtistListDataStore = create<AlbumArtistListDataSlice>()(
devtools(
immer((set) => ({
actions: {
setItemData: (data) => {
set((state) => {
state.itemData = data;
});
},
},
itemData: [],
})),
{ name: 'store_album_list_data' },
),
);
export const useAlbumArtistListStoreActions = () =>
useAlbumArtistListDataStore((state) => state.actions);
export const useAlbumArtistListItemData = () =>
useAlbumArtistListDataStore((state) => {
return { itemData: state.itemData, setItemData: state.actions.setItemData };
});

View file

@ -0,0 +1,36 @@
import create from 'zustand';
import { devtools } from 'zustand/middleware';
import { immer } from 'zustand/middleware/immer';
export interface AlbumListDataState {
itemData: any[];
}
export interface AlbumListDataSlice extends AlbumListDataState {
actions: {
setItemData: (data: any[]) => void;
};
}
export const useAlbumListDataStore = create<AlbumListDataSlice>()(
devtools(
immer((set) => ({
actions: {
setItemData: (data) => {
set((state) => {
state.itemData = data;
});
},
},
itemData: [],
})),
{ name: 'store_album_list_data' },
),
);
export const useAlbumListStoreActions = () => useAlbumListDataStore((state) => state.actions);
export const useAlbumListItemData = () =>
useAlbumListDataStore((state) => {
return { itemData: state.itemData, setItemData: state.actions.setItemData };
});

View file

@ -5,3 +5,5 @@ export * from './album.store';
export * from './song.store'; export * from './song.store';
export * from './album-artist.store'; export * from './album-artist.store';
export * from './playlist.store'; export * from './playlist.store';
export * from './album-list-data.store';
export * from './album-artist-list-data.store';