feat: lazy loaded tanks earch

This commit is contained in:
TrèsAbhi committed 2024-07-09 21:16:20 -05:00
1 parent 6a2631ea72
commit 2286a398cf
3 files changed
+51 -16

No files matched your search

@@ -1,10 +1,25 @@
import { Flex, Skeleton } from '@radix-ui/themes';
import { memo, useRef } from 'react';
import { useIntersection } from '../../../../hooks/useIntersection';
export function SkeletonTankCard() {
return (
<Flex direction="column" gap="2">
<Skeleton height="64px" />
<Skeleton height="1em" />
</Flex>
);
interface SkeletonTankCardProps {
onIntersection?: () => void;
}
export const SkeletonTankCard = memo(
({ onIntersection }: SkeletonTankCardProps) => {
const card = useRef<HTMLDivElement>(null);
useIntersection(() => onIntersection?.(), card, {
disabled: onIntersection === undefined,
});
return (
<Flex direction="column" gap="2" ref={card}>
<Skeleton height="64px" />
<Skeleton height="1em" />
</Flex>
);
},
() => true,
);
@@ -1,7 +1,9 @@
'use client';
import { Callout, Flex, FlexProps, Link, Text } from '@radix-ui/themes';
import { go } from 'fuzzysort';
import { times } from 'lodash';
import { memo, use, useMemo } from 'react';
import { memo, use, useEffect, useMemo, useState } from 'react';
import { AdMidSectionResponsive } from '../../../../../components/AdMidSectionResponsive';
import { ExperimentIcon } from '../../../../../components/ExperimentIcon';
import { TANK_CLASSES } from '../../../../../components/Tanks/components/Item/constants';
@@ -40,6 +42,9 @@ type TankSearchProps = Omit<FlexProps, 'onSelect'> & {
onSelectAll?: (tanks: TankDefinition[]) => void;
};
const PREVIEW_COUNT = 25;
const DEFAULT_LOADED_CARDS = 75;
export const TankSearch = memo<TankSearchProps>(
({ compact, onSelect, onSelectAll, ...props }) => {
const exempt = useAdExempt();
@@ -50,7 +55,7 @@ export const TankSearch = memo<TankSearchProps>(
const awaitedTankNames = use(tankNames);
const filters = TankFilters.use();
const sort = TankopediaSort.use();
const tanks = useMemo(() => {
const tanksFiltered = useMemo(() => {
if (filters.search === undefined) {
const filtered = awaitedTanksDefinitionsArray.filter((tank) =>
filterTank(filters, tank),
@@ -379,6 +384,12 @@ export const TankSearch = memo<TankSearchProps>(
return searchedTanks;
}
}, [filters]);
const [loadedRows, setLoadedRows] = useState(DEFAULT_LOADED_CARDS);
const tanks = tanksFiltered.slice(0, loadedRows);
useEffect(() => {
setLoadedRows(DEFAULT_LOADED_CARDS);
}, [filters, sort]);
return (
<Flex direction="column" gap="4" flexGrow="1" {...props}>
@@ -447,6 +458,22 @@ export const TankSearch = memo<TankSearchProps>(
)}
</>
))}
{times(
Math.min(PREVIEW_COUNT, tanksFiltered.length - loadedRows),
(index) => {
return (
<SkeletonTankCard
key={index}
onIntersection={() => {
setLoadedRows((state) =>
Math.min(state + 2, tanksFiltered.length),
);
}}
/>
);
},
)}
</TankCardWrapper>
)}
-7
View File
@@ -1,19 +1,12 @@
'use client';
import { AdMidSectionResponsive } from '../../../components/AdMidSectionResponsive';
import PageWrapper from '../../../components/PageWrapper';
import { useAdExempt } from '../../../hooks/useAdExempt';
import * as TankFilters from '../../../stores/tankFilters';
import { TankSearch } from './components/TankSearch';
export default function Page() {
const exempt = useAdExempt();
return (
<TankFilters.Provider>
<PageWrapper color="purple" size={1028}>
<TankSearch />
{!exempt && <AdMidSectionResponsive />}
</PageWrapper>
</TankFilters.Provider>
);