Finalize initial swr implementation

This commit is contained in:
Sam Becker 2024-04-25 22:51:09 -05:00
parent a08a2f8fb4
commit 4fa85316e8
6 changed files with 54 additions and 37 deletions

View File

@ -10,12 +10,15 @@ import { usePathname } from 'next/navigation';
import { BiTrash } from 'react-icons/bi';
import MoreMenu from '@/components/MoreMenu';
import { useAppState } from '@/state/AppState';
import { RevalidatePhotos } from '@/photo/InfinitePhotoScroll';
export default function AdminPhotoMenuClient({
photo,
revalidatePhoto,
...props
}: Omit<ComponentProps<typeof MoreMenu>, 'items'> & {
photo: Photo
revalidatePhoto?: RevalidatePhotos
}) {
const { isUserSignedIn } = useAppState();
@ -46,7 +49,7 @@ export default function AdminPhotoMenuClient({
action: () => toggleFavoritePhotoAction(
photo.id,
shouldRedirectFav,
),
).then(() => revalidatePhoto?.()),
}, {
label: 'Delete',
icon: <BiTrash
@ -59,7 +62,9 @@ export default function AdminPhotoMenuClient({
photo.id,
photo.url,
shouldRedirectDelete,
);
).then(() => {
revalidatePhoto?.(true);
});
}
},
},

View File

@ -8,6 +8,9 @@ import SiteGrid from '@/components/SiteGrid';
import Spinner from '@/components/Spinner';
import { getPhotosAction } from '@/photo/actions';
import { useAppState } from '@/state/AppState';
import { Photo } from '.';
export type RevalidatePhotos = (revalidateRemainingPhotos?: boolean) => void;
export default function InfinitePhotoScroll({
key = 'PHOTOS',
@ -15,7 +18,6 @@ export default function InfinitePhotoScroll({
itemsPerPage = 12,
prefetch = true,
triggerOnView = true,
debug = true,
}: {
key?: string
initialOffset?: number
@ -28,27 +30,25 @@ export default function InfinitePhotoScroll({
const buttonRef = useRef<HTMLButtonElement>(null);
const fetcher = useCallback((key: string) => {
if (debug) { console.log('Fetching', key); }
const offset = parseInt(key.split('-')[1]);
return getPhotosAction(
initialOffset + offset * itemsPerPage,
const fetcher = useCallback(([_key, size]: [string, number]) =>
getPhotosAction(
initialOffset + size * itemsPerPage,
itemsPerPage,
key,
);
}, [initialOffset, itemsPerPage, debug]);
)
, [initialOffset, itemsPerPage]);
const { data, isLoading, error, mutate, size, setSize } = useSwrInfinite(
(size: number, prev: []) => prev && prev.length === 0
? null
:`${key}-${size}`,
fetcher,
{
revalidateOnFocus: isUserSignedIn,
revalidateOnReconnect: isUserSignedIn,
revalidateFirstPage: isUserSignedIn,
},
);
const { data, isLoading, error, mutate, size, setSize } =
useSwrInfinite<Photo[]>(
(size: number, prev: []) => prev && prev.length === 0
? null
: [key, size],
fetcher,
{
revalidateOnFocus: isUserSignedIn,
revalidateOnReconnect: isUserSignedIn,
revalidateFirstPage: isUserSignedIn,
},
);
const isFinished = useMemo(() =>
data && data[data.length - 1]?.length < itemsPerPage
@ -56,7 +56,7 @@ export default function InfinitePhotoScroll({
useEffect(() => {
if (prefetch) {
preload(`${key}-${size ?? 0 + 1}`, fetcher);
preload([key, size ?? 0 + 1], fetcher);
}
}, [prefetch, key, size, fetcher]);
@ -81,7 +81,17 @@ export default function InfinitePhotoScroll({
return (
<div className="space-y-4">
{data && <div className="space-y-1">
{data.map((photos, i) => <PhotosLarge key={i} photos={photos} />)}
{data.map((photos, i) =>
<PhotosLarge
key={i}
photos={photos}
revalidatePhotos={(revalidateRemainingPhotos?: boolean) => {
mutate(data, {
revalidate: (_data: any, [_, size]:[string, number]) =>
revalidateRemainingPhotos ? size >= i : size === i,
} as any);
}}
/>)}
</div>}
{!isFinished &&
<SiteGrid

View File

@ -1,3 +1,5 @@
'use client';
import {
Photo,
altTextForPhoto,
@ -19,6 +21,7 @@ import DivDebugBaselineGrid from '@/components/DivDebugBaselineGrid';
import PhotoLink from './PhotoLink';
import { SHOULD_PREFETCH_ALL_LINKS } from '@/site/config';
import AdminPhotoMenuClient from '@/admin/AdminPhotoMenuClient';
import { RevalidatePhotos } from './InfinitePhotoScroll';
export default function PhotoLarge({
photo,
@ -26,6 +29,7 @@ export default function PhotoLarge({
priority,
prefetch = SHOULD_PREFETCH_ALL_LINKS,
prefetchRelatedLinks = SHOULD_PREFETCH_ALL_LINKS,
revalidatePhoto,
showCamera = true,
showSimulation = true,
shouldShareTag,
@ -38,6 +42,7 @@ export default function PhotoLarge({
priority?: boolean
prefetch?: boolean
prefetchRelatedLinks?: boolean
revalidatePhoto?: RevalidatePhotos
showCamera?: boolean
showSimulation?: boolean
shouldShareTag?: boolean
@ -87,7 +92,10 @@ export default function PhotoLarge({
prefetch={prefetch}
/>
<div className="absolute right-0 translate-y-[-4px] z-10">
<AdminPhotoMenuClient photo={photo} />
<AdminPhotoMenuClient {...{
photo,
revalidatePhoto,
}} />
</div>
</div>
<div className="space-y-baseline">

View File

@ -1,15 +1,18 @@
import AnimateItems from '@/components/AnimateItems';
import { Photo } from '.';
import PhotoLarge from './PhotoLarge';
import { RevalidatePhotos } from './InfinitePhotoScroll';
export default function PhotosLarge({
photos,
animate = true,
prefetchFirstPhotoLinks,
revalidatePhotos,
}: {
photos: Photo[]
animate?: boolean
prefetchFirstPhotoLinks?: boolean
revalidatePhotos?: RevalidatePhotos
}) {
return (
<AnimateItems
@ -25,6 +28,7 @@ export default function PhotosLarge({
photo={photo}
priority={index <= 1}
prefetchRelatedLinks={prefetchFirstPhotoLinks && index === 0}
revalidatePhoto={revalidatePhotos}
/>)}
itemKeys={photos.map(photo => photo.id)}
/>

View File

@ -220,14 +220,5 @@ export async function getPhotoItemsAction(query: string) {
: [];
}
export const getPhotosAction = async (
offset: number,
limit: number,
cacheKey: string,
) =>
getPhotosCachedCached({ offset, limit }).then(photos =>
photos.map(photo => ({
...photo,
cacheKey,
}))
);
export const getPhotosAction = async (offset: number, limit: number) =>
getPhotosCachedCached({ offset, limit });

View File

@ -83,7 +83,6 @@ export interface Photo extends PhotoDb {
exposureTimeFormatted?: string
exposureCompensationFormatted?: string
takenAtNaiveFormatted: string
cacheKey?: string
}
export const parsePhotoFromDb = (photoDbRaw: PhotoDb): Photo => {