Refine MoreComponents data fetching
This commit is contained in:
parent
4ba2f1cd0c
commit
d3e837b4f6
@ -1,4 +1,4 @@
|
||||
import { getPhotosCached } from '@/cache';
|
||||
import { getPhotosCached, getPhotosCountCached } from '@/cache';
|
||||
import { generateOgImageMetaForPhotos } from '@/photo';
|
||||
import PhotosEmptyState from '@/photo/PhotosEmptyState';
|
||||
import { Metadata } from 'next';
|
||||
@ -14,20 +14,28 @@ export async function generateMetadata(): Promise<Metadata> {
|
||||
}
|
||||
|
||||
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(() => []);
|
||||
const [
|
||||
photos,
|
||||
count,
|
||||
] = await Promise.all([
|
||||
// Make homepage queries resilient to error on first time setup
|
||||
getPhotosCached({ limit: MAX_PHOTOS_TO_SHOW_OG }).catch(() => []),
|
||||
getPhotosCountCached().catch(() => 0),
|
||||
]);
|
||||
|
||||
return (
|
||||
photos.length > 0
|
||||
? <div className="space-y-1">
|
||||
<PhotosLarge photos={photos} />
|
||||
<MoreComponents
|
||||
label="More photos"
|
||||
itemsPerRequest={MAX_PHOTOS_TO_SHOW_OG}
|
||||
itemsTotalCount={count}
|
||||
componentLoader={async (limit: number) => {
|
||||
'use server';
|
||||
return <PhotosLarge
|
||||
photos={await getPhotosCached({ limit })}
|
||||
photos={(await getPhotosCached({ limit }))
|
||||
.slice(MAX_PHOTOS_TO_SHOW_OG)}
|
||||
/>;
|
||||
}}
|
||||
/>
|
||||
|
||||
@ -1,27 +1,81 @@
|
||||
'use client';
|
||||
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useCallback, useEffect, useRef, useState, useTransition } from 'react';
|
||||
import Spinner from './Spinner';
|
||||
|
||||
export default function MoreComponents({
|
||||
initialOffset = 1,
|
||||
itemsPerRequest,
|
||||
itemsTotalCount,
|
||||
componentLoader,
|
||||
label = 'Load more',
|
||||
triggerOnView = true,
|
||||
}: {
|
||||
initialOffset?: number
|
||||
itemsPerRequest: number
|
||||
itemsTotalCount: number
|
||||
componentLoader: (limit: number) => Promise<JSX.Element>
|
||||
label?: string
|
||||
triggerOnView?: boolean
|
||||
prefetch?: boolean
|
||||
}) {
|
||||
const [offset] = useState(initialOffset);
|
||||
const [offset, setOffset] = useState(1);
|
||||
const [components, setComponents] = useState<JSX.Element[]>([]);
|
||||
|
||||
const [isPending, startTransition] = useTransition();
|
||||
|
||||
const buttonRef = useRef<HTMLButtonElement>(null);
|
||||
|
||||
const advance = useCallback(() => startTransition(() => {
|
||||
setOffset(o => o + 1);
|
||||
}), []);
|
||||
|
||||
useEffect(() => {
|
||||
const getPhotosLargeComponentAsync = async () => {
|
||||
const getMoreComponentsAsync = async () => {
|
||||
console.log('getMoreComponentsAsync', itemsPerRequest * offset);
|
||||
return componentLoader(itemsPerRequest * offset);
|
||||
};
|
||||
getPhotosLargeComponentAsync().then((component) => {
|
||||
getMoreComponentsAsync().then((component) => {
|
||||
setComponents([component]);
|
||||
});
|
||||
}, [componentLoader, itemsPerRequest, offset]);
|
||||
|
||||
return components;
|
||||
useEffect(() => {
|
||||
// Only add observer if button is rendered
|
||||
if (buttonRef.current) {
|
||||
const observer = new IntersectionObserver(e => {
|
||||
if (
|
||||
triggerOnView &&
|
||||
e[0].isIntersecting &&
|
||||
!isPending
|
||||
) {
|
||||
advance();
|
||||
}
|
||||
}, {
|
||||
root: null,
|
||||
threshold: 0,
|
||||
});
|
||||
|
||||
observer.observe(buttonRef.current);
|
||||
|
||||
return () => observer.disconnect();
|
||||
}
|
||||
}, [triggerOnView, advance, isPending]);
|
||||
|
||||
const showMoreButton = itemsTotalCount > itemsPerRequest * offset;
|
||||
|
||||
return <div className="space-y-4">
|
||||
{components}
|
||||
{showMoreButton &&
|
||||
<button
|
||||
ref={buttonRef}
|
||||
className="block w-full subtle"
|
||||
onClick={!triggerOnView ? advance : undefined}
|
||||
disabled={triggerOnView || isPending}
|
||||
>
|
||||
{isPending
|
||||
? <span className="relative inline-block translate-y-[3px]">
|
||||
<Spinner size={16} />
|
||||
</span>
|
||||
: label}
|
||||
</button>}
|
||||
</div>;
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user