Hoist pagination to parent component

This commit is contained in:
Sam Becker 2024-01-14 16:21:39 -06:00
parent 968194c38b
commit 85688d202a
3 changed files with 24 additions and 14 deletions

View File

@ -34,13 +34,14 @@ export default async function HomePage() {
<MoreComponents
label="More photos"
itemsPerRequest={LARGE_PHOTOS_TO_SHOW}
itemsTotalCount={count}
componentLoader={async (limit: number) => {
'use server';
return <PhotosLarge
photos={(await getPhotosCached({ limit }))
.slice(LARGE_PHOTOS_TO_SHOW)}
/>;
return {
component: <PhotosLarge
photos={(await getPhotosCached({ limit }))
.slice(LARGE_PHOTOS_TO_SHOW)} />,
isFinished: limit > count,
};
}}
/>
</Suspense>

View File

@ -6,14 +6,16 @@ import SiteGrid from './SiteGrid';
export default function MoreComponents({
itemsPerRequest,
itemsTotalCount,
componentLoader,
label = 'Load more',
triggerOnView = true,
prefetch = true,
}: {
itemsPerRequest: number
itemsTotalCount: number
componentLoader: (limit: number) => Promise<JSX.Element>
componentLoader: (start: number, offset: number) => Promise<{
component: JSX.Element,
isFinished: boolean,
}>
label?: string
triggerOnView?: boolean
prefetch?: boolean
@ -21,22 +23,31 @@ export default function MoreComponents({
const [offset, setOffset] = useState(2);
const [components, setComponents] = useState<JSX.Element[]>([]);
const [isLoading, setIsLoading] = useState(false);
const [isFinished, setIsFinished] = useState(false);
const buttonRef = useRef<HTMLButtonElement>(null);
const advance = useCallback(() => {
setIsLoading(true);
const getMoreComponentsAsync = async () => {
return componentLoader(itemsPerRequest * offset);
return componentLoader(0, itemsPerRequest * offset);
};
getMoreComponentsAsync()
.then(component => {
.then(({ component, isFinished }) => {
setComponents([component]);
setIsFinished(isFinished);
setOffset(o => o + 1);
})
.finally(() => setIsLoading(false));
}, [componentLoader, itemsPerRequest, offset]);
// useEffect(() => {
// if (prefetch && components.length < offset) {
// console.log('prefetching');
// advance();
// }
// }, [prefetch, advance, components.length, offset]);
useEffect(() => {
// Only add observer if button is rendered
if (buttonRef.current) {
@ -59,11 +70,9 @@ export default function MoreComponents({
}
}, [triggerOnView, advance, isLoading]);
const showMoreButton = itemsTotalCount > itemsPerRequest * (offset - 1);
return <>
{components}
{showMoreButton &&
{!isFinished &&
<SiteGrid
contentMain={
<button

View File

@ -11,7 +11,7 @@ import {
import camelcaseKeys from 'camelcase-keys';
import type { Metadata } from 'next';
export const LARGE_PHOTOS_TO_SHOW = 12;
export const LARGE_PHOTOS_TO_SHOW = 3;
export const GRID_THUMBNAILS_TO_SHOW_MAX = 12;
export const ACCEPTED_PHOTO_FILE_TYPES = [