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 <MoreComponents
label="More photos" label="More photos"
itemsPerRequest={LARGE_PHOTOS_TO_SHOW} itemsPerRequest={LARGE_PHOTOS_TO_SHOW}
itemsTotalCount={count}
componentLoader={async (limit: number) => { componentLoader={async (limit: number) => {
'use server'; 'use server';
return <PhotosLarge return {
photos={(await getPhotosCached({ limit })) component: <PhotosLarge
.slice(LARGE_PHOTOS_TO_SHOW)} photos={(await getPhotosCached({ limit }))
/>; .slice(LARGE_PHOTOS_TO_SHOW)} />,
isFinished: limit > count,
};
}} }}
/> />
</Suspense> </Suspense>

View File

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

View File

@ -11,7 +11,7 @@ import {
import camelcaseKeys from 'camelcase-keys'; import camelcaseKeys from 'camelcase-keys';
import type { Metadata } from 'next'; 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 GRID_THUMBNAILS_TO_SHOW_MAX = 12;
export const ACCEPTED_PHOTO_FILE_TYPES = [ export const ACCEPTED_PHOTO_FILE_TYPES = [