Test new server action component loader

This commit is contained in:
Sam Becker 2024-01-13 13:14:29 -06:00
parent b20717e8b8
commit 88429b97f4
7 changed files with 89 additions and 51 deletions

View File

@ -12,7 +12,7 @@ import {
pathForAdminPhotoEdit,
} from '@/site/paths';
import { titleForPhoto } from '@/photo';
import MorePhotos from '@/photo/MorePhotos';
import MoreComponentsClient from '@/components/MoreComponentsClient';
import {
getBlobPhotoUrlsNoStore,
getPhotosCached,
@ -144,7 +144,10 @@ export default async function AdminPhotosPage({
</Fragment>)}
</AdminGrid>
{showMorePhotos &&
<MorePhotos path={pathForAdminPhotos(offset + 1)} />}
<MoreComponentsClient
label="More photos"
path={pathForAdminPhotos(offset + 1)}
/>}
</div>
</div>}
/>

View File

@ -1,5 +1,5 @@
import { getPhotosCached, getPhotosCountCached } from '@/cache';
import MorePhotos from '@/photo/MorePhotos';
import MoreComponentsClient from '@/components/MoreComponentsClient';
import StaggeredOgPhotos from '@/photo/StaggeredOgPhotos';
import {
PaginationParams,
@ -26,7 +26,10 @@ export default async function GridPage({ searchParams }: PaginationParams) {
<StaggeredOgPhotos photos={photos} />
</div>
{showMorePhotos &&
<MorePhotos path={pathForOg(offset + 1)} />}
<MoreComponentsClient
label="More photos"
path={pathForOg(offset + 1)}
/>}
</div>
);
}

View File

@ -1,19 +1,10 @@
import { getPhotosCached, getPhotosCountCached } from '@/cache';
import AnimateItems from '@/components/AnimateItems';
import MorePhotos from '@/photo/MorePhotos';
import SiteGrid from '@/components/SiteGrid';
import { getPhotosCached } from '@/cache';
import { generateOgImageMetaForPhotos } from '@/photo';
import PhotoLarge from '@/photo/PhotoLarge';
import PhotosEmptyState from '@/photo/PhotosEmptyState';
import {
PaginationParams,
getPaginationForSearchParams,
} from '@/site/pagination';
import { pathForRoot } from '@/site/paths';
import { Metadata } from 'next';
import { MAX_PHOTOS_TO_SHOW_OG } from '@/photo/image-response';
export const dynamic = 'force-static';
import MoreComponents from '@/components/MoreComponents';
import PhotosLarge from '@/photo/PhotosLarge';
export async function generateMetadata(): Promise<Metadata> {
// Make homepage queries resilient to error on first time setup
@ -22,40 +13,24 @@ export async function generateMetadata(): Promise<Metadata> {
return generateOgImageMetaForPhotos(photos);
}
export default async function HomePage({ searchParams }: PaginationParams) {
const { offset, limit } = getPaginationForSearchParams(searchParams, 12);
const [
photos,
count,
] = await Promise.all([
// Make homepage queries resilient to error on first time setup
getPhotosCached({ limit }).catch(() => []),
getPhotosCountCached().catch(() => 0),
]);
const showMorePhotos = count > photos.length;
export default async function HomePage() {
// Make homepage queries resilient to error on first time setup
const photos = await getPhotosCached({ limit: MAX_PHOTOS_TO_SHOW_OG })
.catch(() => []);
return (
photos.length > 0
? <div className="space-y-4">
<AnimateItems
className="space-y-1"
duration={0.7}
staggerDelay={0.15}
distanceOffset={0}
staggerOnFirstLoadOnly
items={photos.map((photo, index) =>
<PhotoLarge
key={photo.id}
photo={photo}
priority={index <= 1}
/>)}
? <div className="space-y-1">
<PhotosLarge photos={photos} />
<MoreComponents
itemsPerRequest={MAX_PHOTOS_TO_SHOW_OG}
componentLoader={async (limit: number) => {
'use server';
return <PhotosLarge
photos={await getPhotosCached({ limit })}
/>;
}}
/>
{showMorePhotos &&
<SiteGrid
contentMain={<MorePhotos path={pathForRoot(offset + 1)} />}
/>}
</div>
: <PhotosEmptyState />
);

View File

@ -0,0 +1,27 @@
'use client';
import { useEffect, useState } from 'react';
export default function MoreComponents({
initialOffset = 1,
itemsPerRequest,
componentLoader,
}: {
initialOffset?: number
itemsPerRequest: number
componentLoader: (limit: number) => Promise<JSX.Element>
}) {
const [offset] = useState(initialOffset);
const [components, setComponents] = useState<JSX.Element[]>([]);
useEffect(() => {
const getPhotosLargeComponentAsync = async () => {
return componentLoader(itemsPerRequest * offset);
};
getPhotosLargeComponentAsync().then((component) => {
setComponents([component]);
});
}, [componentLoader, itemsPerRequest, offset]);
return components;
}

View File

@ -2,14 +2,16 @@
import { useRouter } from 'next/navigation';
import { useCallback, useEffect, useRef, useTransition } from 'react';
import Spinner from '../components/Spinner';
import Spinner from './Spinner';
export default function MorePhotos({
export default function MoreComponentsClient({
path,
label = 'Load more',
triggerOnView = true,
prefetch = true,
}: {
path: string
label?: string
triggerOnView?: boolean
prefetch?: boolean
}) {
@ -59,7 +61,7 @@ export default function MorePhotos({
? <span className="relative inline-block translate-y-[3px]">
<Spinner size={16} />
</span>
: 'More photos'}
: label}
</button>
);
}

View File

@ -3,7 +3,7 @@ import PhotoSmall from './PhotoSmall';
import { clsx } from 'clsx/lite';
import AnimateItems from '@/components/AnimateItems';
import { Camera } from '@/camera';
import MorePhotos from '@/photo/MorePhotos';
import MoreComponentsClient from '@/components/MoreComponentsClient';
import { FilmSimulation } from '@/simulation';
import { GRID_ASPECT_RATIO, HIGH_DENSITY_GRID } from '@/site/config';
@ -79,7 +79,10 @@ export default function PhotoGrid({
</div>).concat(additionalTile ?? [])}
/>
{showMorePath &&
<MorePhotos path={showMorePath} />}
<MoreComponentsClient
label="More photos"
path={showMorePath}
/>}
</div>
);
};

25
src/photo/PhotosLarge.tsx Normal file
View File

@ -0,0 +1,25 @@
import AnimateItems from '@/components/AnimateItems';
import { Photo } from '.';
import PhotoLarge from './PhotoLarge';
export default function PhotosLarge({
photos,
}: {
photos: Photo[]
}) {
return (
<AnimateItems
className="space-y-1"
duration={0.7}
staggerDelay={0.15}
distanceOffset={0}
staggerOnFirstLoadOnly
items={photos.map((photo, index) =>
<PhotoLarge
key={photo.id}
photo={photo}
priority={index <= 1}
/>)}
/>
);
}