feat: fetch the next page of books before the reader hits the bottom

The prefetch zone is a viewport deep rather than 200px, and the observer
re-observes after a page lands so a chain of loads is not cut short.
This commit is contained in:
2026-08-17 13:48:40 -04:00
parent 55e00ba960
commit 0220f2d970
2 changed files with 45 additions and 16 deletions
@@ -29,19 +29,31 @@
$effect(() => {
if (!sentinel || !bookCollection.moreBooks) return;
const target = sentinel;
const observer = new IntersectionObserver(
async (entries) => {
if (entries[0].isIntersecting && !bookCollection.loading) {
await bookCollection.loadMoreBooks();
if (!entries[0].isIntersecting) return;
await bookCollection.loadMoreBooks();
// A page that does not push the sentinel back out of the prefetch zone
// produces no further intersection change, so the observer would sit
// idle until the next scroll. Re-observing asks for a fresh reading.
if (bookCollection.moreBooks) {
observer.unobserve(target);
observer.observe(target);
}
},
{
{
root: scrollContainer,
rootMargin: '0px 0px 200px 0px'
// One viewport of lead time: the next page is requested a full screen
// before the reader reaches the end of the current one.
rootMargin: '0px 0px 100% 0px'
}
);
observer.observe(sentinel);
observer.observe(target);
return () => {
observer.disconnect();
@@ -110,7 +122,7 @@
{#if bookCollection.moreBooks}
<div bind:this={sentinel}>
{#if bookCollection.loading}
{#if bookCollection.loadingMore}
<Spinner />
{/if}
</div>