Refactor infinite scroll component
This commit is contained in:
parent
765f8367e5
commit
eb59e58b1c
@ -10,9 +10,9 @@ import { MAX_PHOTOS_TO_SHOW_OG } from '@/image-response';
|
||||
import { Metadata } from 'next/types';
|
||||
import PhotoGridSidebar from '@/photo/PhotoGridSidebar';
|
||||
import { getPhotoSidebarData } from '@/photo/data';
|
||||
import InfinitePhotoScroll from '@/photo/InfinitePhotoScroll';
|
||||
import { getPhotos } from '@/services/vercel-postgres';
|
||||
import { cache } from 'react';
|
||||
import InfinitePhotoScrollGrid from '@/photo/InfinitePhotoScrollGrid';
|
||||
|
||||
export const dynamic = 'force-static';
|
||||
|
||||
@ -41,8 +41,7 @@ export default async function GridPage() {
|
||||
contentMain={<div className="space-y-0.5 sm:space-y-1">
|
||||
<PhotoGrid {...{ photos }} />
|
||||
{photosCount > photos.length &&
|
||||
<InfinitePhotoScroll
|
||||
type='grid'
|
||||
<InfinitePhotoScrollGrid
|
||||
initialOffset={INFINITE_SCROLL_INITIAL_GRID}
|
||||
itemsPerPage={INFINITE_SCROLL_MULTIPLE_GRID}
|
||||
/>}
|
||||
|
||||
@ -6,10 +6,11 @@ import {
|
||||
import PhotosEmptyState from '@/photo/PhotosEmptyState';
|
||||
import { Metadata } from 'next/types';
|
||||
import { MAX_PHOTOS_TO_SHOW_OG } from '@/image-response';
|
||||
import InfinitePhotoScroll from '../photo/InfinitePhotoScroll';
|
||||
import PhotosLarge from '@/photo/PhotosLarge';
|
||||
import { cache } from 'react';
|
||||
import { getPhotos, getPhotosCount } from '@/services/vercel-postgres';
|
||||
import InfinitePhotoScrollPhotosLarge from
|
||||
'@/photo/InfinitePhotoScrollPhotosLarge';
|
||||
|
||||
export const dynamic = 'force-static';
|
||||
|
||||
@ -43,8 +44,7 @@ export default async function HomePage() {
|
||||
? <div className="space-y-1">
|
||||
<PhotosLarge {...{ photos }} />
|
||||
{photosCount > photos.length &&
|
||||
<InfinitePhotoScroll
|
||||
type="full-frame"
|
||||
<InfinitePhotoScrollPhotosLarge
|
||||
initialOffset={INFINITE_SCROLL_INITIAL_HOME}
|
||||
itemsPerPage={INFINITE_SCROLL_MULTIPLE_HOME}
|
||||
/>}
|
||||
|
||||
@ -1,17 +1,16 @@
|
||||
'use client';
|
||||
|
||||
import useSwrInfinite from 'swr/infinite';
|
||||
import PhotosLarge from '@/photo/PhotosLarge';
|
||||
import {
|
||||
ReactNode,
|
||||
useCallback,
|
||||
useMemo,
|
||||
useRef,
|
||||
} from 'react';
|
||||
import SiteGrid from '@/components/SiteGrid';
|
||||
import Spinner from '@/components/Spinner';
|
||||
import { getPhotosAction } from '@/photo/actions';
|
||||
import { getPhotosCachedAction, getPhotosAction } from '@/photo/actions';
|
||||
import { Photo } from '.';
|
||||
import PhotoGrid from './PhotoGrid';
|
||||
import { clsx } from 'clsx/lite';
|
||||
import { useAppState } from '@/state/AppState';
|
||||
|
||||
@ -20,19 +19,31 @@ export type RevalidatePhoto = (
|
||||
revalidateRemainingPhotos?: boolean,
|
||||
) => Promise<any>;
|
||||
|
||||
export default function InfinitePhotoScroll({
|
||||
type = 'full-frame',
|
||||
initialOffset,
|
||||
itemsPerPage,
|
||||
}: {
|
||||
type: 'full-frame' | 'grid'
|
||||
export type InfinitePhotoScrollExternalProps = {
|
||||
initialOffset: number
|
||||
itemsPerPage: number
|
||||
debug?: boolean
|
||||
}
|
||||
|
||||
export default function InfinitePhotoScroll({
|
||||
cacheKey,
|
||||
initialOffset,
|
||||
itemsPerPage,
|
||||
wrapMoreButtonInGrid,
|
||||
useCachedPhotos = true,
|
||||
children,
|
||||
}: InfinitePhotoScrollExternalProps & {
|
||||
cacheKey: string
|
||||
wrapMoreButtonInGrid: boolean
|
||||
useCachedPhotos?: boolean
|
||||
children: (props: {
|
||||
photos: Photo[]
|
||||
onLastPhotoVisible: () => void
|
||||
revalidatePhoto?: RevalidatePhoto
|
||||
}) => ReactNode
|
||||
}) {
|
||||
const { swrTimestamp, isUserSignedIn } = useAppState();
|
||||
|
||||
const key = `${swrTimestamp}-${type}`;
|
||||
const key = `${swrTimestamp}-${cacheKey}`;
|
||||
|
||||
const keyGenerator = useCallback(
|
||||
(size: number, prev: Photo[]) => prev && prev.length === 0
|
||||
@ -40,12 +51,17 @@ export default function InfinitePhotoScroll({
|
||||
: [key, size]
|
||||
, [key]);
|
||||
|
||||
const fetcher = useCallback(([_key, size]: [string, number]) => {
|
||||
return getPhotosAction(
|
||||
initialOffset + size * itemsPerPage,
|
||||
itemsPerPage,
|
||||
);
|
||||
}, [initialOffset, itemsPerPage]);
|
||||
const fetcher = useCallback(([_key, size]: [string, number]) =>
|
||||
useCachedPhotos
|
||||
? getPhotosCachedAction(
|
||||
initialOffset + size * itemsPerPage,
|
||||
itemsPerPage,
|
||||
)
|
||||
: getPhotosAction(
|
||||
initialOffset + size * itemsPerPage,
|
||||
itemsPerPage,
|
||||
)
|
||||
, [useCachedPhotos, initialOffset, itemsPerPage]);
|
||||
|
||||
const { data, isLoading, isValidating, error, mutate, setSize } =
|
||||
useSwrInfinite<Photo[]>(
|
||||
@ -106,17 +122,12 @@ export default function InfinitePhotoScroll({
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
{type === 'full-frame'
|
||||
? <PhotosLarge {...{
|
||||
photos,
|
||||
revalidatePhoto,
|
||||
onLastPhotoVisible: advance,
|
||||
}} />
|
||||
: <PhotoGrid {...{
|
||||
photos,
|
||||
onLastPhotoVisible: advance,
|
||||
}} />}
|
||||
{!isFinished && (type === 'full-frame'
|
||||
{children({
|
||||
photos,
|
||||
onLastPhotoVisible: advance,
|
||||
revalidatePhoto,
|
||||
})}
|
||||
{!isFinished && (wrapMoreButtonInGrid
|
||||
? <SiteGrid contentMain={renderMoreButton()} />
|
||||
: renderMoreButton())}
|
||||
</div>
|
||||
|
||||
26
src/photo/InfinitePhotoScrollGrid.tsx
Normal file
26
src/photo/InfinitePhotoScrollGrid.tsx
Normal file
@ -0,0 +1,26 @@
|
||||
'use client';
|
||||
|
||||
import InfinitePhotoScroll, {
|
||||
InfinitePhotoScrollExternalProps,
|
||||
} from './InfinitePhotoScroll';
|
||||
import PhotoGrid from './PhotoGrid';
|
||||
|
||||
export default function InfinitePhotoScrollGrid({
|
||||
initialOffset,
|
||||
itemsPerPage,
|
||||
}: InfinitePhotoScrollExternalProps) {
|
||||
return (
|
||||
<InfinitePhotoScroll
|
||||
cacheKey="Grid"
|
||||
initialOffset={initialOffset}
|
||||
itemsPerPage={itemsPerPage}
|
||||
wrapMoreButtonInGrid={false}
|
||||
>
|
||||
{({ photos, onLastPhotoVisible }) =>
|
||||
<PhotoGrid {...{
|
||||
photos,
|
||||
onLastPhotoVisible,
|
||||
}} />}
|
||||
</InfinitePhotoScroll>
|
||||
);
|
||||
}
|
||||
27
src/photo/InfinitePhotoScrollPhotosLarge.tsx
Normal file
27
src/photo/InfinitePhotoScrollPhotosLarge.tsx
Normal file
@ -0,0 +1,27 @@
|
||||
'use client';
|
||||
|
||||
import InfinitePhotoScroll, {
|
||||
InfinitePhotoScrollExternalProps,
|
||||
} from './InfinitePhotoScroll';
|
||||
import PhotosLarge from './PhotosLarge';
|
||||
|
||||
export default function InfinitePhotoScrollPhotosLarge({
|
||||
initialOffset,
|
||||
itemsPerPage,
|
||||
}: InfinitePhotoScrollExternalProps) {
|
||||
return (
|
||||
<InfinitePhotoScroll
|
||||
cacheKey="PhotosLarge"
|
||||
initialOffset={initialOffset}
|
||||
itemsPerPage={itemsPerPage}
|
||||
wrapMoreButtonInGrid
|
||||
>
|
||||
{({ photos, onLastPhotoVisible, revalidatePhoto }) =>
|
||||
<PhotosLarge {...{
|
||||
photos,
|
||||
onLastPhotoVisible,
|
||||
revalidatePhoto,
|
||||
}} />}
|
||||
</InfinitePhotoScroll>
|
||||
);
|
||||
}
|
||||
@ -195,9 +195,12 @@ export async function streamAiImageQueryAction(
|
||||
streamOpenAiImageQuery(imageBase64, AI_IMAGE_QUERIES[query]));
|
||||
}
|
||||
|
||||
export const getPhotosAction = async (offset: number, limit: number) =>
|
||||
export const getPhotosCachedAction = async (offset: number, limit: number) =>
|
||||
getPhotosCachedCached({ offset, limit });
|
||||
|
||||
export const getPhotosAction = async (offset: number, limit: number) =>
|
||||
getPhotos({ offset, limit });
|
||||
|
||||
export const queryPhotosByTitleAction = async (query: string) =>
|
||||
(await getPhotos({ query, limit: 10 }))
|
||||
.filter(({ title }) => Boolean(title));
|
||||
|
||||
Loading…
Reference in New Issue
Block a user